File inst-source-utils-2018.12.10.obscpio of Package inst-source-utils

07070100000000000081A40000000000000000000000015C0E85F60000464B000000000000000000000000000000000000002500000000inst-source-utils-2018.12.10/COPYING		    GNU GENERAL PUBLIC LICENSE
		       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 51 Franklin Steet, Fifth Floor, Boston, MA  02111-1307  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

		    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

			    NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

		     END OF TERMS AND CONDITIONS

	    How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA  02111-1307  USA


Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Library General
Public License instead of this License.
07070100000001000081A40000000000000000000000015C0E85F600003657000000000000000000000000000000000000003700000000inst-source-utils-2018.12.10/inst-source-utils.changes-------------------------------------------------------------------
Fri Apr  6 10:02:20 UTC 2018 - adrian@suse.de

- add support for transalted EULA

-------------------------------------------------------------------
Tue Mar 13 12:27:40 UTC 2018 - adrian@suse.de

- new susedata i18n structure
- move source to git

-------------------------------------------------------------------
Tue Feb 27 15:17:48 CET 2018 - ro@suse.de

- mk_changelog: do not use localtime call for min_date
  (bnc#1081766)

-------------------------------------------------------------------
Fri Jul 28 13:26:40 CEST 2017 - ro@suse.de

- drop requires for recode 

-------------------------------------------------------------------
Tue Jul 26 12:07:52 CEST 2016 - ro@suse.de

- ABXML: add diskusage data to susedata xml structure
  (fate#320517) 

-------------------------------------------------------------------
Mon May  2 17:46:57 CEST 2016 - ro@suse.de

- RPMQ: add infrastructure for HEADERSTART and EXTRA
- create_package_descr: use infrastucture to allow running with
  only rpm headers instead of full rpms (bnc#978085) 

-------------------------------------------------------------------
Wed Dec  9 16:01:55 CET 2015 - ro@suse.de

- update rezip_repo_rsyncable again: fix up filenames if they
  are checksum prefixed, do not change timestamps of the
  files recompressed (bnc#958511) 

-------------------------------------------------------------------
Tue Dec  8 12:10:41 CET 2015 - ro@suse.de

- rezip_repo_rsyncable: add "-n" option for gzip 

-------------------------------------------------------------------
Tue Oct 27 15:10:49 CET 2015 - ro@suse.de

- mk_listings: set LC_CTYPE (bnc#910388)
- ABXML.pm: add endoflife in product structure

-------------------------------------------------------------------
Tue Mar 18 16:40:34 CET 2014 - ro@suse.de

- update create_package_descr: fix utf8 handling thanks to mls 

-------------------------------------------------------------------
Fri Mar 14 02:38:32 CET 2014 - ro@suse.de

- create_sha1sums: skip content file actions if content file
  does not exist 

-------------------------------------------------------------------
Wed Mar 12 17:56:59 CET 2014 - ro@suse.de

- fix bogus code in rezip-repo-rsyncable 

-------------------------------------------------------------------
Wed Mar  5 14:34:28 CET 2014 - ro@suse.de

- bump version number and add automatic to pre_checkin.sh 

-------------------------------------------------------------------
Tue Mar  4 16:47:58 CET 2014 - ro@suse.de

- add ABXML.pm and ABStructured.pm
- rewrite rezip_repo_rsyncable to keep checksum type 
- add requires for perl-XML-Parser

-------------------------------------------------------------------
Tue Feb 25 15:36:18 CET 2014 - ro@suse.de

- fix typo in last change 

-------------------------------------------------------------------
Wed Feb 19 17:51:38 CET 2014 - ro@suse.de

- update create_package_descr: also recognize new rpm tags
  for Suggests and Enhances (thanks to mls for the patch) 

-------------------------------------------------------------------
Fri Sep 20 11:57:36 CEST 2013 - ro@suse.de

- also add Requires(pre) and Requires(post) to Prq sections 

-------------------------------------------------------------------
Wed Apr  3 12:03:43 CEST 2013 - ro@suse.de

- remove pdb code from create_package_descr
- create_sha1sums: replace "which" by "type -p"
- create_repo_for_patch.sh: same change
- RPMQ: fix for name-version-release > 64 characters 

-------------------------------------------------------------------
Fri Jan 25 01:23:46 CET 2013 - ro@suse.de

- use "strict" for create_package_descr
- add support for -e (eula_dir) parameter in create_package_descr 

-------------------------------------------------------------------
Wed Dec  5 13:27:11 CET 2012 - ro@suse.de

- update create_md5sums to get the key files witout a pubring.gpg

-------------------------------------------------------------------
Thu Sep 13 16:15:54 CEST 2012 - ro@suse.de

- add recent fixes 

-------------------------------------------------------------------
Wed Feb 29 10:55:46 CET 2012 - ro@suse.de

- mk_changelog: calculate time (two years ago) differently to
  avoid error on leap days. 

-------------------------------------------------------------------
Thu Feb  2 11:10:39 UTC 2012 - adrian@suse.de

- write SHA256 sums into CHECKSUMS file

-------------------------------------------------------------------
Sun Oct 16 19:55:51 UTC 2011 - lars@linux-schulserver.de

- to too much quoting in create_package_descr

-------------------------------------------------------------------
Fri Oct 14 17:04:57 UTC 2011 - lrupp@suse.de

- handle spaces in path in create_package_descr (bnc#604730)

-------------------------------------------------------------------
Wed May 25 08:18:37 UTC 2011 - adrian@suse.de

- fix header generation for SHA256 mode (no SHA1 tag)

-------------------------------------------------------------------
Thu May  5 12:20:17 CEST 2011 - ro@suse.de

- create_sha1sum and create_sha1sums now understand option "-2"
  to use/create sha256sum(s)

-------------------------------------------------------------------
Thu Apr 28 18:25:28 CEST 2011 - ro@suse.de

- add option -D to use sha256 checksums in create_package_descr 

-------------------------------------------------------------------
Wed Mar 17 11:52:48 CET 2010 - ro@suse.de

- add requires to recode 

-------------------------------------------------------------------
Mon Feb 22 12:11:17 CET 2010 - ro@suse.de

- create_package_descr: output a little statistic 

-------------------------------------------------------------------
Wed Jan 27 14:52:59 UTC 2010 - adrian@suse.de

- add Requires to gpg2 to fix product media signing

-------------------------------------------------------------------
Mon Nov  2 13:41:07 CET 2009 - ro@suse.de

- add rezip_repo_rsyncable 
- update create_package_descr:
  - skip deltarpms
  - write comment with cmdline only once
  - do not warn for missing pdb data
- update: create_repo_for_patch.sh
  - add sources if wanted
- update: create_sha1sums
  - clear LANG LANGUAGE
- update: createpatch
  - major overhaul
- update: RPMQ.pm
  - add PRETRANS,POSTTRANS, ..., FILEDIGESTALGO

-------------------------------------------------------------------
Mon Oct 12 23:14:14 CEST 2009 - lrupp@suse.de

- fix bnc#546152: create_sha1sums fails to find custom gpg-key on 
  non-english systems  
- fix create_package_descr to work with delta-rpms in path

-------------------------------------------------------------------
Fri Aug  7 19:47:34 CEST 2009 - lrupp@suse.de

- create_package_descr: disable debug output for missing pdb data
- create_repo_for_patch.sh: complete rework (thanks to Ulf Lange)
  fixes bnc #506357
- RPMQ.pm: added the following RPM-tags 
  PRETRANS, POSTTRANS, PRETRANSPROG, POSTTRANSPROG, DISTTAG, 
  FILEDIGESTALGOS, FILEDIGESTALGO
- createpatch: first part of the code rewrite is done
  New options: -l|--logfile => write output to logfile
               -b|--basedir => obsoletes old script behavior 
               -c|--configfile => use options from configfile

-------------------------------------------------------------------
Mon Jul 13 12:40:12 CEST 2009 - ug@suse.de

- remove the "PATTERNS" line from the created add_on
  (create_update_source)

-------------------------------------------------------------------
Fri Mar  6 11:58:45 CET 2009 - ro@suse.de

- create_package_descr: add -Q option to disable Shr tag 

-------------------------------------------------------------------
Wed Feb 25 11:10:27 CET 2009 - lrupp@suse.de

- create_package_descr: more help text for the -T XTAGS_FILE 
- create_sha1sum, create_md5sums - fix bnc#460894: handle multiple
  arguments

-------------------------------------------------------------------
Fri Jan 23 12:33:54 CET 2009 - jcborn@suse.de

- added gen-s390-cd-kernel.pl because it is required to create
  bootable S/390 media with kiwi-isntsource

-------------------------------------------------------------------
Mon Nov 24 15:12:14 CET 2008 - ro@suse.de

- update create_package_descr 

-------------------------------------------------------------------
Mon Nov 24 13:53:46 CET 2008 - lrupp@suse.de

- fix pathnames

-------------------------------------------------------------------
Thu Nov 20 12:42:40 CET 2008 - ro@suse.de

- create_package_descr: add -T option for xtags file
  format: "packagename: literal text" so that "literal text"
  will be directly included for the package data

-------------------------------------------------------------------
Thu Nov 13 00:14:01 CET 2008 - ro@suse.de

- mk_listings: exclude .cr-cache and .snapshot 

-------------------------------------------------------------------
Thu Oct 16 17:54:47 CEST 2008 - lrupp@suse.de

- create_sha1sums:
  + also put the GPG key in each slideshow directory

-------------------------------------------------------------------
Thu Oct 16 15:00:19 CEST 2008 - ro@suse.de

- create_package_descr:
  + add "-V" option to also put the vendor for each rpm in
  the generated metadata 

-------------------------------------------------------------------
Thu Oct  9 17:46:48 CEST 2008 - lrupp@suse.de

- quick fix for bnc#409927:
  - create_sha1sums:
    + create SHA1SUM files and sign them in the slideshow directory
  - added create_sha1sum which is a copy of create_md5sums 
    (can't use create_sha1sum_s_ as this name is already in use)
- removed NoSource tags 

-------------------------------------------------------------------
Mon Jul 21 19:02:27 CEST 2008 - lrupp@suse.de

- create_directory_yast:
  + add "-f" option to overwrite existing directory.yast files
- create_md5sums:
  + small code cleanups only
- create_package_descr:
  + added option -F (do file list: packages.FL)
  + added option -B (add requires for src packages)
  + fix warning message if -x is not specified (typo)
  + EXTRA_REQUIRES_FILE option switched from -p to -r
- create_repo_for_patch.sh:
  + fix quoting
- create_sha1sums: 
  + added option "-x" to add additional meta files in content file
  + beetter check for repomd.xml
  + added "-n" option to skip re-signing
- mk_changelog:
  + small code cleanup

-------------------------------------------------------------------
Fri May 16 16:52:36 CEST 2008 - ro@suse.de

- patches upstreamed 

-------------------------------------------------------------------
Thu May 15 15:09:25 CEST 2008 - schwab@suse.de

- Fix syntax and quoting bugs.

-------------------------------------------------------------------
Fri Feb  1 15:03:24 CET 2008 - lrupp@suse.de

- fix file permissions (fixes bnc#357313 and bnc#351070)
- handle also boot/*/config boot/*/common (create_sha1sums)
- fix path to REPOFILE (create_sha1sums)

-------------------------------------------------------------------
Tue Dec 11 14:30:39 CET 2007 - lrupp@suse.de

- added mk_changelog (for add-on creator)
- add fallback mode for createpatch (see #308684)

-------------------------------------------------------------------
Wed Sep 26 20:38:37 CEST 2007 - ro@suse.de

- remove dependency to createrepo for now 

-------------------------------------------------------------------
Wed Sep 26 12:20:24 CEST 2007 - lrupp@suse.de

- fixes for Bug #308684:
  + require createrepo
  + be more secure in bash

-------------------------------------------------------------------
Tue Jul 17 02:08:14 CEST 2007 - lrupp@suse.de

- createpatch: use CONFIRMATION_FILE as description to make clear, 
  that this creates a confirmation popup for the user (#205534)

-------------------------------------------------------------------
Fri Jul 13 11:21:25 CEST 2007 - lrupp@suse.de

- create_md5sums:
  + fix typo in usage
- create_package_descr:
  + search data in main package for xxbit packages
  + add license notes as confirmlic so YaST can display them 
    even in plain text mode
- create_sha1sums: added to generate the SHA1SUMs in content file
- createpatch:
  + support "license_to_confirm": add an EULA to the patch, read 
    from the file specified (see #205534 for details)
  + beautify usage message
  + added @packagelist to condition
- mk_listings:
  + handle whitespaces in directory names
  + use --rsyncable as gzip option: `rsync' program can take 
    advantage of similarities during sync over network
  + replace standard Names (CD,DVD,inst-source)
  + use '--nodigest --nosignature' for rpm queries if supported
  + re-create hardlinks from basedir to CD-dir if CD*/*.gz exists

-------------------------------------------------------------------
Tue May 15 15:55:26 CEST 2007 - ories@suse.de

- added support for adding supplements tag (#262859, #256038)
- added support for overwriting the default freshens value 
- fixed one \" escaping typo
- do not delete product.xml

-------------------------------------------------------------------
Thu Mar 15 18:20:28 CET 2007 - lrupp@suse.de

- patched copy-sources.sh

-------------------------------------------------------------------
Tue Mar 13 12:06:48 CET 2007 - lrupp@suse.de

- fixed source again - fixed script, too 

-------------------------------------------------------------------
Fri Mar  9 10:39:06 CET 2007 - lrupp@suse.de

- fixed source tarball

-------------------------------------------------------------------
Mon Mar  5 15:24:17 CET 2007 - lrupp@suse.de

- add package to SLE10-SP1 tree (#250860)

-------------------------------------------------------------------
Mon Feb 26 14:17:43 CET 2007 - lrupp@suse.de

- fixed #214273 :  inst-source-utils perl module in subdir of 
  /usr/bin is questionable/ugly

-------------------------------------------------------------------
Thu Oct 19 20:07:28 CEST 2006 - lrupp@suse.de

- Obsolete only autoyast-utils <= 2.14.6

-------------------------------------------------------------------
Fri Oct 13 18:02:18 CEST 2006 - lrupp@suse.de

- Initial version

07070100000002000081A40000000000000000000000015C0E85F6000006C4000000000000000000000000000000000000003400000000inst-source-utils-2018.12.10/inst-source-utils.spec#
# spec file for package inst-source-utils
#
# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.

# Please submit bugfixes or comments via http://bugs.opensuse.org/
#


Name:           inst-source-utils
Summary:        Utilities for creating customized installation sources
License:        GPL-2.0-or-later
Group:          System/YaST
Version:        2018.04.06
Release:        0
Url:            http://en.opensuse.org/Inst-source-utils
BuildArch:      noarch
Requires:       gpg2
Obsoletes:      autoyast2-utils <= 2.14.10
Provides:       autoyast2-utils = 2.14.10
Recommends:     create-repo-utils
Requires:       perl-XML-Parser
Source:         %name-%version.tar.xz
Source1:        split.pl
BuildRoot:      %{_tmppath}/%{name}-%{version}-build

%description
Utilities supporting autoinstallation and creation of customized
installation  sources.

Have a look at http://en.opensuse.org/Inst-source-utils for a detailed
description of each script.



%prep
%setup -q

%build

%install
install -d -m 755 %{buildroot}/%{_prefix}

cp -a usr %{buildroot}/

%files
%doc COPYING
%defattr(755,root,root,755)
%_bindir/*
%defattr(644,root,root,755)
%_datadir/%name

%changelog
07070100000003000041ED0000000000000000000000045C0E85F600000000000000000000000000000000000000000000002100000000inst-source-utils-2018.12.10/usr07070100000004000041ED0000000000000000000000025C0E85F600000000000000000000000000000000000000000000002500000000inst-source-utils-2018.12.10/usr/bin07070100000005000081ED0000000000000000000000015C0E85F600000498000000000000000000000000000000000000003700000000inst-source-utils-2018.12.10/usr/bin/compress_susetags#!/usr/bin/perl

use strict;
use File::stat;

my $rsyncable = "";

my $arg = shift @ARGV;
my $tmpdir = `mktemp -d /tmp/mk_listings.XXXXXX`;
chomp ($tmpdir);
if ( $arg ) {
    die("need an argument") unless ( -d $arg );
}

if ( $arg !~ /^\// ) {
    my $pwd = `pwd`;
    chomp ($pwd);
    $arg = "$pwd/$arg";
}

system (`touch "$tmpdir/fff"`);
system (`gzip -f --rsyncable "$tmpdir/fff" >/dev/null 2>/dev/null`);
if ( -f "$tmpdir/fff.gz" ) {
    $rsyncable = "--rsyncable";
}
system (`rm -f "$tmpdir/fff" "$tmpdir/fff.gz"`);

for my $packfile (glob("$arg/packages*"),glob("$arg/*.pat")) {
    next if ( $packfile !~ /^[A-Z0-9\-\._]*$/i );
    next unless ( -f "$packfile" || -l "$packfile" );
    next if ( $packfile =~ /\.gz$/ );
    if ( -l "$packfile" ) {
	my $l = `readlink $packfile`;
	chomp ($l);
	next if ( $packfile =~ /\.gz$/ );
	$l .= ".gz" unless ( $l =~ /\.gz$/ );
	system ("rm", "-f", $packfile );
        system ("ln", "-s", "-f", $l, $packfile.'.gz');
	next;
    }
    system ("gzip", "-f", "-9", $rsyncable, $packfile);
}

system("rm", "-r", "-f", $tmpdir);
system("rm", "-f", "$arg/patterns");
chdir($arg);
system("ls *.pat *.pat.gz > patterns 2>/dev/null");

07070100000006000081ED0000000000000000000000015C0E85F6000006F3000000000000000000000000000000000000003B00000000inst-source-utils-2018.12.10/usr/bin/create_directory.yast#!/bin/bash
#
# Copyright (C) 2006 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# $Id: create_directory.yast,v 1.3 2008/06/25 12:10:43 lrupp Exp lrupp $
#

FORCE="no"

function usage (){
    echo
    echo "Usage: $(basename $0) [-f] <targetdir>"
    echo
    echo "       f : force - recreates existing files"
    echo
    echo "       Creates the file directory.yast in each subdirectory."
    echo "       YaST needs this file during Network installation to"
    echo "       \"see\" the content of the directory if the server"
    echo "       doesn't support directory listings."
    echo
    exit $1
}

if [ -z "$1" ]; then
  usage 1;
fi

while getopts 'fh' OPTION; do
	case $OPTION in
		f) FORCE="yes"
		;;
		h) usage 1;
		;;
	esac
done
shift $(( OPTIND - 1 ))

DIR="$1"

test -d "$DIR" || { 
  echo "ERROR:   directory $DIR not found" >&2
  usage 1
}

for i in $(ls "$DIR") ; do
    case "$i" in
	  *directory.yast)
		if [ "$FORCE" != "yes" ]; then
	    	continue
		fi
	  ;;
    esac
    if test -d "$DIR/$i" ; then
		echo "$i/"
    else
		echo "$i"
    fi
done > "$DIR/directory.yast"

07070100000007000081ED0000000000000000000000015C0E85F600000DE2000000000000000000000000000000000000003400000000inst-source-utils-2018.12.10/usr/bin/create_md5sums#!/bin/bash
#
# Copyright (C) 2006 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# $Id: create_md5sums 110 2009-03-06 15:30:14Z lrupp $
#

function usage (){
    echo
    echo "Usage: `basename $0` [--meta] <targetdir>"
    echo "       --meta : also create MD5SUMS.meta file"
    echo "       --quiet: don't output anything"
    echo 
    echo "       Creates MD5SUMS files in each subdirectory."
    echo "       Sometimes useful for debugging inst-source problems ;-)"
    echo
    exit $1
}

function output(){
    if [ "$QUIET" != "yes" ]; then
        echo "$1"
    fi
}

if [ -z "$1" ]; then
  usage 1;
fi
if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]] ; then
  usage 0;
fi

unset LANGUAGE
unset LANG
export LC_ALL=POSIX
umask 022

CREATE_META=
QUIET="no"

if test "x$1" = "x--meta"; then
    CREATE_META=1
    shift
fi
if test "x$1" = "x--quiet"; then
    QUIET="yes"
    shift
fi

ROOTDIRS="$*"
TMPFILE=$(mktemp /tmp/.create_md5sums.XXXXXX)
MYPWD=$(pwd)

for ROOTDIR in "$@" ; do
    case "$ROOTDIR" in
	/*) ;;
	*) ROOTDIR="$MYPWD/$ROOTDIR" ;;
    esac

    test -d "$ROOTDIR" || {
        echo "WARNING: $ROOTDIR is not a directory.  Skipping it."
    }

    find "$ROOTDIR" -type d | while read DIR; do
        cd "$DIR"
        unset FILES
        NFILES=0
        for FILE in * ; do
            test -f "$FILE" || continue
            test -L "$FILE" && continue
            test -n "$MD5SUMS_SKIPFILES" && {
                IS_SKIP=false
                set -f
                for i in $MD5SUMS_SKIPFILES ; do
                    set +f
                    case "$FILE" in
                      ($i)
                        IS_SKIP=true
                        break
                        ;;
                    esac
                done
                set +f
                test $IS_SKIP = true && continue
            }
            case "$FILE" in
              (*.swp|MD5SUMS*|SHA1SUMS*)
                continue
                ;;
              (*)
                FILES[$[++NFILES]]="$FILE"
                ;;
            esac
          done
        if [ $NFILES -eq 0 ]; then
            rm -f MD5SUMS*
        else
            echo -n > $TMPFILE
            for FILE in "${FILES[@]}"; do
                md5sum "$FILE" >> $TMPFILE;
            done
            test -e MD5SUMS || touch MD5SUMS
	        cmp -s $TMPFILE MD5SUMS || {
                mv $TMPFILE MD5SUMS
				chmod 644 MD5SUMS
                output "INFO:   created MD5SUMS in $DIR"
	        }
	    if test -n "$CREATE_META"; then
            test -e MD5SUMS.meta || touch MD5SUMS.meta
            md5sum MD5SUMS > $TMPFILE
            cmp -s $TMPFILE MD5SUMS.meta || {
		        mv $TMPFILE MD5SUMS.meta
                chmod 644 MD5SUMS.meta
                output "INFO:   created MD5SUMS.meta in $DIR"
            }
	    fi
            rm -f $TMPFILE
        fi
    done
done
07070100000008000081ED0000000000000000000000015C0E85F600005AEB000000000000000000000000000000000000003A00000000inst-source-utils-2018.12.10/usr/bin/create_package_descr#!/usr/bin/perl
#
# Copyright (C) 2006 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# $Id: create_package_descr,v 1.29 2008/06/24 18:42:26 lrupp Exp lrupp $
#

BEGIN {
  $abuild_base_dir = "/usr/share/inst-source-utils";
  unshift @INC, "$abuild_base_dir/modules";
}

$| = 1;

use File::stat;
use FileHandle;
use strict;
use RPMQ;
use Digest::MD5 ();
use Encode;

my (@DATADIRS,@IGNOREDIRS,@LANGUAGES,%SEEN_PACKAGE,%IGNORE_PACKAGE,@SHA_CACHEDIR);
my %lang_alias = ( "czech"=>"cs",
                   "english"=>"en",
                   "french"=>"fr",
                   "german"=>"de",
                   "italian"=>"it",
                   "russian" => "ru",
                   "spanish"=>"es",
                   "hungarian"=>"hu" );
my %tag_short = ("description"=>"Des","notice"=>"Ins","delnotice"=>"Del");
my $ignored_packages = "";
my $ignore_sources = "0";
my $ignore_symlinks = "0";
my $prefer_yastdescr = "0";
my $add_licenses = "0";
my $do_checksums = "0";
my $do_sha256 = "0";
my $do_keywords = "0";
my $have_sha_cache = 0;
my $do_file_list = 0;
my $maxdepth = 255;
my $src_requires = 0;
my $default_lang="english";
my $add_vendor = 0;
my $allow_shr = 1;
my %used_fallbacks;
my $checksum_binary = "sha1sum";
my $unused_data_dir = "";
my $eula_data_dir = "";
my $ignore_file = "";
my $ignore_dir = "";
my $output_dir = "";
my $extra_requires = "";
my $extra_provides = "";
my $extra_tags = "";
my $with_links = "";
my $use_headers = "0";

my %xprovlist;
my %xreqlist;
my %xtaglist;
my %pkg_lang;

sub usage {
    my $exit_code=shift || 1;
    print "Usage: create_package_descr [OPTIONS]\n";
    print "       [-d DATADIR1 [-d DATADIR2 [... ] ] ] (default cwd)\n";
    print "       [-e EULA_DIR ]\n";
    print "       [-x EXTRA_PROV_FILE ]\n";
    print "       [-r EXTRA_REQUIRES_FILE]\n";
    print "       [-i IGNORE_DIR [ -i IGNORE_DIR [... ] ] ]\n";
    print "       [-I IGNORE_FILE ]\n";
    print "       [-l LANG1 [-l LANG2 [... ] ]  (default $default_lang)\n";
    print "       [-o OUTPUT_DIR ]              (default `cwd`/setup/descr)\n";
    print "       [-c CACHE_DIR ]               (default none)\n";
    print "       [-M MAXDEPTH ]                (default $maxdepth, depth for du-file)\n";
    print "       [-T XTAGS_FILE ]              (extra tags for the packages file)\n";
    print "       [-Z ]                         (add_licenses)\n";
    print "       [-V ]                         (add_vendor for each rpm)\n";
    print "       [-S ]                         (ignore_sources)\n";
    print "       [-P ]                         (prefer_yastdescr)\n";
    print "       [-L ]                         (ignore_symlinks)\n";
    print "       [-C ]                         (do_checksums)\n";
    print "       [-D ]                         (do_sha256_checksums)\n";
    print "       [-K ]                         (do_keywords)\n";
    print "       [-F ]                         (do_file_list)\n";
    print "       [-B ]                         (add requires for src packages)\n\n";
    print "       [-Q ]                         (never use Shr tags)\n";
    print "       [-H ]                         (Use headers)\n\n";
	print "       Note: the -T option allows to add additional tags to the\n";
	print "             resulting packages file.\n";
	print "             The file should contain the package name, a colon and\n";
	print "             a whitespace. Afterwards, additional tags in one line\n";
	print "             (newlines can be produced via \\n).\n";
	print "             Example: 3ddiag: +Kwd:\\nsupport_l3\\n-Kwd:\n";
    exit $exit_code;
}

sub filter_weak {
  my ($r, $tn, $tf) = @_;
  my @tf = @{$r->{$tf} || []};
  my @res;
  for (@{$r->{$tn}}) {
    push @res, $_ unless (shift @tf) & 0x8000000;
  }
  return @res;
}

sub filter_strong {
  my ($r, $tn, $tf) = @_;
  my @tf = @{$r->{$tf} || []};
  my @res;
  for (@{$r->{$tn}}) {
    push @res, $_ if (shift @tf) & 0x8000000;
  }
  return @res;
}

my @SAVEARGS;

for (@ARGV) {
   push @SAVEARGS, $_;
}

while ( my $arg = shift ( @ARGV ) ) {
  if ( $arg eq "-d" ) { push @DATADIRS , shift @ARGV ; }
  elsif ( $arg eq "-B" ) { $src_requires = 1; }
  elsif ( $arg eq "-V" ) { $add_vendor = 1; }
  elsif ( $arg eq "-C" ) { $do_checksums = "1"; }
  elsif ( $arg eq "-D" ) { $do_checksums = "1";  $do_sha256 = "1"; $checksum_binary = "sha256sum"; }
  elsif ( $arg eq "-F" ) { $do_file_list = 1; }
  elsif ( $arg eq "-H" ) { $use_headers = 1; }
  elsif ( $arg eq "-I" ) { $ignore_file = shift @ARGV ; }
  elsif ( $arg eq "-K" ) { $do_keywords = "1"; }
  elsif ( $arg eq "-L" ) { $ignore_symlinks = "1"; }
  elsif ( $arg eq "-M" ) { $maxdepth = shift @ARGV ; }
  elsif ( $arg eq "-P" ) { $prefer_yastdescr = "1"; }
  elsif ( $arg eq "-S" ) { $ignore_sources = "1"; }
  elsif ( $arg eq "-Z" ) { $add_licenses = "1" ; }
  elsif ( $arg eq "-Q" ) { $allow_shr = 0; }
  elsif ( $arg eq "-c" ) { push @SHA_CACHEDIR , shift @ARGV ; }
  elsif ( $arg eq "-i" ) { push @IGNOREDIRS, shift @ARGV ; }
  elsif ( $arg eq "-l" ) { push @LANGUAGES , shift @ARGV ; }
  elsif (( $arg eq "-h" ) || ( $arg eq "--help" )) { shift @ARGV ; usage(0); }
  elsif ( $arg eq "-o" ) { $output_dir = shift @ARGV ; }
  elsif ( $arg eq "-p" ) { $unused_data_dir = shift @ARGV ; }
  elsif ( $arg eq "-e" ) { $eula_data_dir = shift @ARGV ; }
  elsif ( $arg eq "-r" ) { $extra_requires = shift @ARGV ; }
  elsif ( $arg eq "-x" ) { $extra_provides = shift @ARGV ; }
  elsif ( $arg eq "-T" ) { $extra_tags = shift @ARGV ; }
  else {
	 print STDERR "\nunknown parameter $arg\n\n";
     usage(1);
  }
}

if ( $ignore_symlinks eq "1" ) {
  $with_links = "-type f";
} else {
  $with_links = "";
}

for (@SHA_CACHEDIR) {
    $have_sha_cache++ if ( -d $_ );
}

push @DATADIRS , "." unless ( @DATADIRS );
push @LANGUAGES , "$default_lang" unless ( @LANGUAGES );
$output_dir = "./setup/descr/" unless ( $output_dir );

print "INFO:    datadirs       : ".join(",",@DATADIRS)."\n";
print "INFO:    languages      : ".join(",",@LANGUAGES)."\n";
print "INFO:    output dir     : $output_dir\n";

if ( $extra_provides ) {
  if ( -f $extra_provides ) {
    print "INFO:    extra_provides : $extra_provides\n";
    %xprovlist = %{ReadFileToHash( $extra_provides )};
  } else {
    print "WARNING: extra_provides : file $extra_provides not found!\n";
  }
} else {
    print "WARNING: -x not specified\n";
    print "WARNING: this means all provides like /bin/sh will be missing\n";
}

if ( $extra_requires ) {
  if ( -f $extra_requires ) {
    print "INFO:    extra_requires : $extra_requires\n";
    %xreqlist = %{ReadFileToHash( $extra_requires )};
  } else {
    print "WARNING: extra_requires : file $extra_requires not found!\n";
  }
}
if ( $extra_tags ) {
  if ( -f $extra_tags ) {
    print "INFO:    extra_tags : $extra_tags\n";
    %xtaglist = %{ReadFileToHash( $extra_tags )};
  } else {
    print "WARNING: extra_tags : file $extra_tags not found!\n";
  }
}

unless ( -d "$output_dir" ) {
	print "INFO:    creating output directory $output_dir\n";
	mkdir_p("$output_dir");
}

if ( @IGNOREDIRS ) {
  foreach $ignore_dir (@IGNOREDIRS) {
    if ( -d "$ignore_dir" && opendir ( IGNDIR, "$ignore_dir") ) {
      while ( my $ign = readdir( IGNDIR ) ) {
        next if ( $ign =~ /^\./ );
        $IGNORE_PACKAGE{$ign} = "yes";
      }
      closedir ( IGNDIR );
      print "INFO:    ignoring packages listed in directory $ignore_dir\n";
    }
  }
}

if ( "$ignore_file" ) {
  if ( -f "$ignore_file" && open ( IGNFILE, "$ignore_file" ) ) {
    while ( my $ign = <IGNFILE> ) {
      chomp ( $ign );
      $IGNORE_PACKAGE{$ign} = "yes";
    }
    close ( IGNFILE );
    print "INFO:    ignoring packages listed in file $ignore_file\n";
  }
}

if ( $ignore_sources eq "1" ) {
    print "WARNING: ignoring all source packages\n";
}

my $pkg_main = OpenFileWrite ( "$output_dir/packages" );
WriteSEntry( $pkg_main, "Ver", "2.0" );
foreach my $lang (@LANGUAGES) {
  $pkg_lang{$lang} = OpenFileWrite ( "$output_dir/packages.$lang_alias{$lang}" );
  WriteSEntry( $pkg_lang{$lang}, "Ver", "2.0" );
}
my $pkg_du = OpenFileWrite ( "$output_dir/packages.DU" );
my $pkg_fl = OpenFileWrite ( "$output_dir/packages.FL" ) if $do_file_list;

WriteSEntry( $pkg_du, "Ver", "2.0" );
WriteSEntry( $pkg_fl, "Ver", "2.0" ) if $do_file_list;

my $media_number = 0;
my $allcounter = 0;
my $wrote_comment = 0;

foreach my $datapath (@DATADIRS) {
  $media_number++;
  open ( FIND, "find '$datapath' -maxdepth 2 $with_links -name \"*.[rs]pm\" -print | sort |" );
  my @pkg_arr = ();
  my @src_arr = ();
  while ( <FIND> ) {
    chomp ( $_ );
    next if (/\.delta\.rpm$/);
    if ( /\.spm$/ || /src\.rpm$/ ) {
	push @src_arr, $_;
    } else {
	push @pkg_arr, $_;
    }
  }
  close ( FIND );
  foreach my $package (@pkg_arr,@src_arr) {
   $allcounter++;
   print "INFO:    CD$media_number - Pkg: $allcounter\r" if ( -t STDOUT );
   my $filespec = "$package";
   chomp ( $filespec );
   $filespec =~ /\/([^\/]*)$/;
   my $filename = $1;
   my $filesize;
   # name, version, release, arch, obsolete, requires, provides,
   # conflicts, copyright, group, buildtime, size, sourcerpm
   my %res = RPMQ::rpmq_many("$package", 1000, 1001, 1002, 1022,
                                         1090, 1114, 1115,
                                         1047, 1112, 1113,
                                         1049, 1048, 1050,
                                         1054, 1053, 1055,
                                         1156, 1157, 1158,
                                         1159, 1160, 1161,
                                         1027, 1116, 1117, 1118, 1030, 1028, 1095, 1096,
                                         1014, 1016, 1006, 1009, 1044, 1004, 1005, 1011, 1124,
                                         5046, 5047, 5048, 5049, 5050, 5051,
                                         5052, 5053, 5054, 5055, 5056, 5057, "HEADERSTART", "SIGTAG_SIZE", "EXTRA"
   );

   # skip delta rpms (if PAYLOADFORMAT eq drpm)
   next if ($res{1124}[0] && $res{1124}[0] eq "drpm");
   #
   my $data = $res{"SIGTAG_SIZE"}[0];
   my $header = $res{"HEADERSTART"}[0];

   my @depexcl = $res{1054};
   my @prereq = rpmq_add_req_flagsvers(\%res, 1049, 1048, 1050); # requires
   RPMQ::rpmq_add_flagsvers(\%res, 1047, 1112, 1113); # provides
   RPMQ::rpmq_add_flagsvers(\%res, 1090, 1114, 1115); # obsoletes
   RPMQ::rpmq_add_flagsvers(\%res, 1054, 1053, 1055); # conflicts

   RPMQ::rpmq_add_flagsvers(\%res, 1156, 1158, 1157) if $res{1156}; # oldsuggests
   RPMQ::rpmq_add_flagsvers(\%res, 1159, 1161, 1160) if $res{1159}; # oldenhances

   RPMQ::rpmq_add_flagsvers(\%res, 5046, 5048, 5047) if $res{5046}; # recommends
   RPMQ::rpmq_add_flagsvers(\%res, 5049, 5051, 5050) if $res{5049}; # suggests
   RPMQ::rpmq_add_flagsvers(\%res, 5052, 5054, 5053) if $res{5052}; # supplements
   RPMQ::rpmq_add_flagsvers(\%res, 5055, 5057, 5056) if $res{5055}; # enhances

   my $rpm_name = $res{1000}[0];
   if ( $IGNORE_PACKAGE{$rpm_name} && $IGNORE_PACKAGE{$rpm_name} eq "yes" ) {
      $ignored_packages .= " $rpm_name";
      next;
   }
   my @pack_path = split('/',"$package");
   pop @pack_path; # filename
   pop @pack_path; # dirname / rpm-arch
   my $pack_basedir = join('/',@pack_path);

   my $checksum = "";
   my $dummy = "";
   my $hash = "";
   my $DULIST;
   my $FLIST;
   my $file_arch;
   my %pacdata;

   if ( $use_headers eq "1" ){
      $filesize = $res{'EXTRA'}[0]{size};
   } else {
      $filesize = $data + $header;
   }
   my $srcrpm = $res{1044}[0];
   $srcrpm =~ s/^(.*)-([^-]*)-([^-]*)\.([^\.]*)\.rpm$/$1 $2 $3 $4/;
   if ($do_checksums eq "1" && $use_headers ne "1") {
	if ( $have_sha_cache ne "0" ) {
		my %qq = RPMQ::rpmq_many("$package", qw{SIGTAG_GPG SIGTAG_PGP SIGTAG_SHA1});
		if ( %qq ) {
			for (qw{SIGTAG_GPG SIGTAG_PGP SIGTAG_SHA1}) {
				$hash .= join('', @{$qq{$_} || []});
			}
			$hash = Digest::MD5::md5_hex($hash);
		}
		for (@SHA_CACHEDIR) {
		    if ( -f "$_/$rpm_name-$hash" ) {
			open ( CSC, "< $_/$rpm_name-$hash" );
			$checksum = <CSC>;
			chomp ($checksum);
			close ( CSC );
			#print "INFO: re_using checksum for $package ($checksum)\n";
		    }
		}
		if ($do_sha256 eq "1") {
		    $checksum = "" unless length($checksum) == 64;
		} else {
		    $checksum = "" unless length($checksum) == 40;
		}
	}
	if ( ! $checksum ) {
        if ( $res{1044}[0] || $ignore_sources eq "0") {
            ($checksum,$dummy) = split('\s+',`$checksum_binary '$package'`);
		    if ( $have_sha_cache eq "1" ) {
			    open ( CSC, "> $SHA_CACHEDIR[0]/$rpm_name-$hash" );
			    print CSC $checksum;
			    close ( CSC );
			    #print "INFO: wrote checksum for $package ($checksum)\n";
            }
        }
   }
   }
   if ($use_headers eq "1") {
      if ($checksum_binary == "sha1sum") {
	  $checksum = $res{'EXTRA'}[0]{sha1};
      }elsif ($checksum_binary == "sha256sum"){
	  $checksum = $res{'EXTRA'}[0]{sha256};
      }
   }
   if ( $res{1044}[0] ) {
	($DULIST,$FLIST) = RpmToDulist($maxdepth, \%res, '');
	$file_arch = $res{1022}[0];
   } else {
	next if ( $ignore_sources eq "1" );
	# has no source, so it is a source
	if ( $filename =~ /\.spm$/ ) {
		$file_arch = "src";
	} else {
		$file_arch = "$filename";
		$file_arch =~ s/^.*\.([^\.]*)\.rpm$/$1/;
	}
	($DULIST,$FLIST) = RpmToDulist($maxdepth, \%res, 'usr/src/packages/');
   }
   my %x_prov = ();
   if ( $xprovlist{"$rpm_name.$file_arch"} ) {
     foreach my $xprov (split('\s', $xprovlist{"$rpm_name.$file_arch"} )) {
	$x_prov{$xprov} = 1;
     }
   }
   # should be else if, but merging both is needed right now
   if ( $xprovlist{$rpm_name} ) {
     foreach my $xprov (split('\s', $xprovlist{$rpm_name} )) {
	$x_prov{$xprov} = 1;
     }
   }
   # add createrepo-style file provides (/etc/*,*bin/*,/usr/lib/sendmail)
   foreach $filename (@{$res{1027}}) {
       $x_prov{$filename} = 1 if ( $filename =~ /^\/etc\// || $filename =~ /bin\// || $filename eq "/usr/lib/sendmail" );
   }
   push @{$res{1047}}, sort keys %x_prov;
   # adding additional requires for a package (but not for src packages)
   if ($xreqlist{$rpm_name} && $res{1044}[0]) {
     foreach my $xreq (split('\s', $xreqlist{$rpm_name} )) {
       push (@{$res{1049}},$xreq);
     }
   }

    WriteSeparator( $pkg_main );
    WriteComment( $pkg_main, @SAVEARGS ) unless $wrote_comment;
    WriteSeparator( $pkg_main ) unless $wrote_comment;
    $wrote_comment = 1;
    WriteSEntry( $pkg_main, "Pkg", "$res{1000}[0] $res{1001}[0] $res{1002}[0] $file_arch");
    if ($do_sha256 eq "1") {
	WriteSEntry( $pkg_main, "Cks", "SHA256 $checksum") if ($checksum);
    } else {
	WriteSEntry( $pkg_main, "Cks", "SHA1 $checksum") if ($checksum);
    }
    if ( $res{1044}[0] ) {
    	# has src, so it's a binary package
    	WriteMEntry( $pkg_main, "Req", @{$res{1049}} );
    	WriteMEntry( $pkg_main, "Prq", @prereq );
    	WriteMEntry( $pkg_main, "Prv", @{$res{1047}} );
    	WriteMEntry( $pkg_main, "Con", @{$res{1054}} );
    	WriteMEntry( $pkg_main, "Obs", @{$res{1090}} );
    	WriteMEntry( $pkg_main, "Rec", @{$res{5046}} ) if $res{5046};
    	WriteMEntry( $pkg_main, "Rec", filter_strong(\%res, 1156, 1158)) if !$res{5046} && $res{1156};
    	WriteMEntry( $pkg_main, "Sug", @{$res{5049}} ) if $res{5049};
    	WriteMEntry( $pkg_main, "Sug", filter_weak(\%res, 1156, 1158)) if !$res{5049} && $res{1156};
    	WriteMEntry( $pkg_main, "Sup", @{$res{5052}} ) if $res{5052};
    	WriteMEntry( $pkg_main, "Sup", filter_strong(\%res, 1159, 1161)) if !$res{5052} && $res{1159};
    	WriteMEntry( $pkg_main, "Enh", @{$res{5055}} ) if $res{5055};
    	WriteMEntry( $pkg_main, "Enh", filter_weak(\%res, 1159, 1161)) if !$res{5055} && $res{1159};
    	WriteSEntry( $pkg_main, "Grp", $res{1016}[0] );
    	WriteSEntry( $pkg_main, "Lic", $res{1014}[0] );
    	WriteSEntry( $pkg_main, "Vnd", $res{1011}[0] ) if $add_vendor;
    	WriteSEntry( $pkg_main, "Src", $srcrpm );
	    WriteSEntry( $pkg_main, "Tim", $res{1006}[0] );
        WriteSEntry( $pkg_main, "Loc", "$media_number $filename");
    } else {
	    WriteMEntry( $pkg_main, "Req", @{$res{1049}} ) if $src_requires;
        WriteSEntry( $pkg_main, "Loc", "$media_number $filename $file_arch");
    }
    WriteSEntry( $pkg_main, "Siz", "$filesize $res{1009}[0]" );

    WriteAnyEntry( $pkg_main, $xtaglist{$rpm_name} ) if ($xtaglist{$rpm_name} && $res{1044}[0]);

    if ($SEEN_PACKAGE{"$rpm_name $res{1001}[0] $res{1002}[0]"} && $allow_shr) {
	    my $found_in = $SEEN_PACKAGE{"$rpm_name $res{1001}[0] $res{1002}[0]"};
	    WriteSEntry( $pkg_main, "Shr", "$res{1000}[0] $res{1001}[0] $res{1002}[0] $found_in");
    } else {
	    foreach my $lang (@LANGUAGES) {
			WriteSeparator( $pkg_lang{$lang} );
			WriteSEntry( $pkg_lang{$lang}, "Pkg", "$res{1000}[0] $res{1001}[0] $res{1002}[0] $file_arch");
			WriteSEntry( $pkg_lang{$lang}, "Sum", "$res{1004}[0]" );
			WriteMEntry( $pkg_lang{$lang}, "Des", split('\n', $res{1005}[0] ));
			if ( $add_licenses eq "1" && -f "$eula_data_dir/$rpm_name.en") {
				open (LIC,"$eula_data_dir/$rpm_name.en");
				my @license = <LIC>;
				close (LIC);
				WriteMEntry( $pkg_lang{$lang}, "Eul", @license);
			}
				
	    }
    }
    WriteSeparator( $pkg_du );
    WriteSEntry( $pkg_du, "Pkg", "$res{1000}[0] $res{1001}[0] $res{1002}[0] $file_arch");
    WriteMEntry( $pkg_du, "Dir", @{$DULIST} );
    if ($do_file_list) {
		WriteSeparator( $pkg_fl );
		WriteSEntry( $pkg_fl, "Pkg", "$res{1000}[0] $res{1001}[0] $res{1002}[0] $file_arch");
		WriteMEntry( $pkg_fl, "Fls", @{$FLIST} );
    }
    $SEEN_PACKAGE{"$rpm_name $res{1001}[0] $res{1002}[0]"} = $file_arch unless $SEEN_PACKAGE{"$rpm_name $res{1001}[0] $res{1002}[0]"};
  }
}
print "INFO:    processed $allcounter packages in $media_number volumes\n";
if ( $ignored_packages ) {
    print "INFO:    following packages were ignored: $ignored_packages\n";
}

close ( $pkg_main );
foreach my $lang (@LANGUAGES) {
  close ( "$pkg_lang{$lang}" );
}
close ( $pkg_du );
close ( $pkg_fl ) if $do_file_list;

#####################################################################
#####################################################################

sub mkdir_p {
  my $dir = shift;

  return 1 if -d "$dir";
  if ($dir =~ /^(.*)\//) {
    mkdir_p("$1") || return undef;
  }
  return undef if !mkdir("$dir", 0777);
  return 1;
}

sub OpenFileWrite {
  my $filename = shift;
  my ($FH) = new FileHandle;
  open ($FH, ">$filename") || die "ERROR: can't write output file $filename";
  return $FH;
}

sub OpenFileRead {
  my $filename = shift;
  my ($FH) = new FileHandle;
  open ($FH, "<$filename") || die "ERROR: can't read input file $filename";
  return $FH;
}

sub ReadFileToHash {
  my ($filename) = @_;
  my (%temp);
  my $FH = OpenFileRead( "$filename" );
  while (<$FH>) {
    chomp ($_);
    last if ( $_ =~ /^:END/ );
    next if ( $_ =~ /^\#/ );
    next if ( $_ =~ /^\s$/ );
    my ($le,$ri) = split (/:/, $_, 2 );
    $le =~ s/^\s*(.*)\s*$/$1/;
    $ri =~ s/^\s*(.*)\s*$/$1/;
    $ri =~ s/\\n/\n/g;
    $temp{$le}=$ri;
  }
  close ($FH);
  \%temp;
}

sub WriteSeparator {
  my ($FH) = shift;
  print $FH "##----------------------------------------\n";
}

sub WriteComment {
  my ($FH,@XX) = @_;
  print $FH "## ".join(" ",@XX)."\n";
}

sub utf8ify {
  my ($value) = @_;
  eval {
    Encode::_utf8_on($value);
    $value = encode('UTF-8', $value, Encode::FB_CROAK);
  };
  if ($@) {
    Encode::_utf8_off($value);
    $value = encode('UTF-8', $value, Encode::FB_DEFAULT);
  }
  Encode::_utf8_off($value);
  return $value;
}

sub WriteAnyEntry {
  my ($FH,$value) = @_;
  $value = utf8ify($value) if $value =~ /[\200-\377]/s;
  print $FH "$value\n";
}

sub WriteSEntry {
  my ($FH,$tag,$value) = @_;
  if ( $value ) {
    $value = utf8ify($value) if $value =~ /[\200-\377]/s;
    print $FH "=$tag: $value\n";
  }
}

sub WriteMEntry {
  my ($FH,$tag,@value) = @_;
  if ( @value && $value[0] ) {
    my $value = join("\n", @value);
    $value = utf8ify($value) if $value =~ /[\200-\377]/s;
    print $FH "+$tag:\n$value\n-$tag:\n";
  }
}

sub RpmToDulist {
  my $maxdepth = shift;
  my $res = shift;
  my $prefix = shift;
  
  if (!$res->{1027}) {
    my @newfl = ();
    my @di = @{$res->{1116} || []};
    for (@{$res->{1117} || []}) {
      my $di = shift @di;
      push @newfl, $res->{1118}->[$di] . $_;
    }
    $res->{1027} = [ @newfl ];
  }
  my @modes = @{$res->{1030} || []};
  my @devs = @{$res->{1095} || []};
  my @inos = @{$res->{1096} || []};
  my @names = @{$res->{1027} || []};
  my @sizes = @{$res->{1028} || []};
  my %seen = ();
  my %dirnum = ();
  my %subdirnum = ();
  my %dirsize = ();
  my %subdirsize = ();
  my ($name, $first);
  my @flist = ();
  for $name (@names) {
    my $mode = shift @modes;
    my $dev = shift @devs;
    my $ino = shift @inos;
    my $size = shift @sizes;
    # strip leading slash
    # prefix is either empty or ends in /
    $name =~ s/^\///;
    $name = "$prefix$name";
    push @flist, "/$name";

    # check if regular file
    next if ($mode & 0170000) != 0100000;
    # don't count hardlinks twice
    next if $seen{"$dev $ino"};
    $seen{"$dev $ino"} = 1;

    # rounded size in kbytes
    $size = int ($size / 1024) + 1;

    $name = '' unless $name =~ s/\/[^\/]*$//;
    if ( ($name =~ tr/\///) < $maxdepth ) {
		$dirsize{"$name/"} += $size;
		$dirnum{"$name/"} += 1;
		$subdirsize{"$name/"} ||= 0;	# so we get all keys
    }
    # traverse though path stripping components from the back
    $name =~ s/\/[^\/]*$// while ( ($name =~ tr/\///) > $maxdepth );

    while ($name ne '') {
		$name = '' unless $name =~ s/\/[^\/]*$//;
		$subdirsize{"$name/"} += $size;
		$subdirnum{"$name/"} += 1;
    }
  }
  my @dulist = ();
  for $name (sort keys %subdirsize) {
    next unless $dirsize{$name} || $subdirsize{$name};
    $dirsize{$name} ||= 0;
    $subdirsize{$name} ||= 0;
    $dirnum{$name} ||= 0;
    $subdirnum{$name} ||= 0;
    push @dulist, "$name $dirsize{$name} $subdirsize{$name} $dirnum{$name} $subdirnum{$name}";
  }
  return \@dulist,\@flist;
}

sub rpmq_add_req_flagsvers {
  my $res = shift;
  my $name = shift;
  my $flags = shift;
  my $vers = shift;
  my @prereq = ();
  return unless $res;
  my @flags = @{$res->{$flags} || []};
  my @vers = @{$res->{$vers} || []};
  for (@{$res->{$name}}) {
    if (@flags && ($flags[0] & 0xe) && @vers) {
      $_ .= ' ';
      $_ .= '<' if $flags[0] & 2;
      $_ .= '>' if $flags[0] & 4;
      $_ .= '=' if $flags[0] & 8;
      $_ .= " $vers[0]";
    }
    # set on RPMSENSE_PREREQ, RPMSENSE_SCRIPT_PRE and RPMSENSE_SCRIPT_POST
    if ( $flags[0] & (64+512+1024) ) {
      push ( @prereq, $_ );
    }
    shift @flags;
    shift @vers;
  }
  return @prereq;
}

07070100000009000081ED0000000000000000000000015C0E85F600001E83000000000000000000000000000000000000003E00000000inst-source-utils-2018.12.10/usr/bin/create_repo_for_patch.sh#!/bin/bash
#
# create_repo_for_patch.sh
#
# Copyright (C) 2006 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# $Id: create_repo_for_patch.sh 182 2009-08-07 17:39:16Z lrupp $
#

MYSTART=$(pwd)
PATCHESFILE="patches.xml"
PREFIX="patch-"
DEBUG=""
SIGN_ID=""
RPMDIR="$(pwd)"
REPODIR="$(pwd)"
PREFIX="patch-"
INCSRC=""

function usage (){
    echo
    echo "Usage: $(basename $0) [options] <source directory containing RPMs> <target directory>"
    echo "       -h          : help (this message)"
    echo "       -p          : patch files (if not located in <target_directory>)"
    echo "       -P          : prefix for patchfiles (default: $PREFIX)"
    echo "       -S          : detached sign the repomd.xml file"
    echo "       -l          : set symlink to source directory"
    echo "       -s          : include source rpms"
    echo "       -I <KEY_ID> : key-id to use for signing the repomd.xml file, if not given"
    echo "                     gpg will try to use the default signing key"
    echo "       -v          : be verbose"
    echo
    echo " example: $0 -S /srv/install/ ."
    echo
    echo "WARING: $(basename $0) will delete all files except patch files in <target directory> !"
    echo
    exit $1
}

function check_binary(){
    local BINARY=$(type -p $1 2>/dev/null)
    if [ x"$BINARY" = x"" ]; then
        echo "ERROR:   $1 not found! Please install the missing package first!" >&2
        exit 3
    fi
    if [ -x "$BINARY" ]; then
        echo "$BINARY"
    else
        echo "ERROR:   $BINARY found but is not executable - please fix!" >&2
        exit 3
    fi
}


if [ ! "$1" ]; then
    usage 1
fi

while getopts 'hvSI:p:P:ls' OPTION ; do
    case $OPTION in
        h) usage 0
        ;;
        p) PATCHDIR="$OPTARG"
        ;;
        P) PREFIX="$OPTARG"
        ;;
        l) LINKRPM="1"
        ;;
        s) INCSRC="1"
        ;;
        S) SIGN="yes"
        ;;
        I) SIGN_ID="$OPTARG"
        ;;
        v) DEBUG="1"
        ;;
        *) usage 1
        ;;
    esac
done
shift $(( OPTIND - 1 ))

RPMDIR="$1"
REPODIR="$2"

CREATEREPO=$(check_binary "createrepo")
if [ $? != 0 ]; then
	exit
fi

if [ -z "$RPMDIR" ]; then
 echo "ERROR:   source directory not defined" >&2
 usage 1
fi

if [ -z "$REPODIR" ]; then
 echo "ERROR:   target directory not defined" >&2
 usage 1
fi

if [ -d "$REPODIR/repodata.tmp" ]; then
    echo "ERROR:   $REPODIR/repodata.tmp exists - exiting" >&2
    exit 1
fi       

mkdir -p "$REPODIR/repodata.tmp" || { echo "ERROR:   Cannot create ${REPODIR}/repodata.tmp"; exit 5; }

PATCHDIR=${PATCHDIR-/$RPMDIR}
echo "INFO:   --- Looking for Patches in Patchdirectory: ${PATCHDIR}"
for i in $(find "${PATCHDIR}/" -name "${PREFIX}*"); do
	[ "$DEBUG" ] && echo "INFO:    Copying patch: $i"
    cp "$i" "$REPODIR/repodata.tmp/" || { echo "ERROR: Cannot copy $i" >&2; exit 7; }
    PATCHFILES="$PATCHFILES $(basename $i)"
done

[ -d "$REPODIR/repodata" ] && rm -r "$REPODIR/repodata"
[ -d "$REPODIR/.olddata" ] && rm -r "$REPODIR/.olddata"
mkdir "$REPODIR/repodata"
 
if [ "${LINKRPM}" ]; then
	echo "INFO:   --- Linking rpms from ${RPMDIR}"
	ln -s "${RPMDIR}/rpm" ${REPODIR} || echo "WARNING: Cannot create link to ${REPODIR}" >&2
else
	echo "INFO:   --- Copying RPMs from $RPMDIR"
    [ -d "${REPODIR}/rpm" ] && rm -r $REPODIR/rpm/*
	[ "$INCSRC" ] && mkdir -p "$REPODIR/rpm/src/"
fi

for patchfile in $(ls "$REPODIR"/repodata.tmp/${PREFIX}*); do
	patch=$(basename "$patchfile")
	for rpmfile in $(grep "location href" "$patchfile"  | cut -d "\"" -f2); do
		arch_dir=$(dirname "$rpmfile" | xargs basename)
		if [ "${LINKRPM}" ]; then
			continue # do not copy files
		else
			[ -d "$REPODIR/rpm/$arch_dir" ] || mkdir -p "$REPODIR/rpm/$arch_dir"
		fi
		if [[ $rpmfile == *.delta.rpm ]]; then continue; fi
		if [[ $rpmfile == *.patch.rpm ]]; then continue; fi
		[ "$DEBUG" ] && echo "INFO:    Copying file: $RPMDIR/$rpmfile to $REPODIR/rpm/$arch_dir/"
		cp -a "$RPMDIR/$rpmfile" "$REPODIR/rpm/$arch_dir/" 2>/dev/null || { echo "ERROR:   Cannot copy $RPMDIR/$rpmfile" >&2; exit 8; }
		if ! [ "${INCSRC}" ]; then continue; fi # Include source files?
		SRCRPM=$(rpm -qp --nodigest --nosignature --qf "%{SOURCERPM}" "$RPMDIR/$rpmfile")
		[ "$DEBUG" ] && echo "INFO:    Copying file: ${RPMDIR}/rpm/src/${SRCRPM}"
		cp -a "$RPMDIR/rpm/src/$SRCRPM" "$REPODIR/rpm/src/" 2>/dev/null || echo "WARNING: Cannot copy source rpm ${RPMDIR}/rpm/src/${SRCRPM}" >&2
	done
done

#
# createrepo
#
echo "INFO:   --- Creating repodata with createrepo"
if [ "$DEBUG" ]; then
  echo "INFO:    Running command: ${CREATEREPO} -p -x "*.delta.rpm" -x "*.patch.rpm" $REPODIR"
  $CREATEREPO -p -x "*.delta.rpm" -x "*.patch.rpm" "$REPODIR" 2>/dev/null 1>&2
else
  $CREATEREPO -q -x "*.delta.rpm" -x "*.patch.rpm" "$REPODIR" 2>/dev/null 1>&2
fi

#
# patches.xml
#
echo "INFO:   --- Creating new file $REPODIR/repodata/$PATCHESFILE"
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > "$REPODIR/repodata/$PATCHESFILE"
echo "<patches xmlns=\"http://novell.com/package/metadata/suse/patches\">" >> "$REPODIR/repodata/$PATCHESFILE"
for patch in $(ls "$REPODIR/repodata.tmp"/patch*); do
	patchname=$(basename "$patch")
    patchid=$(basename "$patchname" .xml)
    sha1=$(sha1sum "$patch" | awk '" " { print $1 }')
    mv "$REPODIR/repodata.tmp/$patchname" "$REPODIR/repodata/" || next;
	echo "  <patch id=\"$patchid\">" >> "$REPODIR/repodata/$PATCHESFILE"
	echo "    <checksum type=\"sha\">$sha1</checksum>" >> "$REPODIR/repodata/$PATCHESFILE"
    echo "    <location href=\"repodata/$patchname\"/>" >> "$REPODIR/repodata/$PATCHESFILE"
	echo "  </patch>" >> "$REPODIR/repodata/$PATCHESFILE"
done
echo "</patches>" >> "$REPODIR/repodata/$PATCHESFILE"

#
# repomd.xml
#
echo "INFO:   --- patching $REPODIR/repodata/repomd.xml"
sha1=$(sha1sum "$REPODIR/repodata/$PATCHESFILE" | awk '" " { print $1 }')
timestamp=$(date +"%Y%m%d%H")
cat >"$REPODIR/repodata.tmp/repomd.xml.patch$$" <<EOF
  <data type="patches">
    <location href="repodata/patches.xml"/>
    <checksum type="sha">$sha1</checksum>
    <timestamp>$timestamp</timestamp>
    <open-checksum type="sha">$sha1</open-checksum>
  </data>
</repomd>
EOF
sed -i '/.*<\/repomd>.*/d' "$REPODIR/repodata/repomd.xml" || { echo 'ERROR: sed command failed!' >&2; exit 9; }
cat "$REPODIR/repodata.tmp/repomd.xml.patch$$" >> "$REPODIR/repodata/repomd.xml"
rm -r "$REPODIR/repodata.tmp"

#
# repomd.xml.key
#
if [ "$SIGN" == "yes" ]; then
	echo "INFO:   --- Signing repomd.xml"
    if [ "${SIGN_ID}" = "" ]; then
		if [ -f "/etc/sign.conf" ]; then
			[ "$DEBUG" ] && echo "INFO:   Try to sign with key from /etc/sign.conf"
			if [ -x $(type -p sign) ]; then
				$(type -p sign) -d "$REPODIR/repodata/repomd.xml"
			else
				echo "ERROR:  Could not execute 'sign'" >&2
				exit 1;
			fi
		else
        	gpg -a -b "${REPODIR}/repodata/repomd.xml"
		fi
       	SIGN_ID=$(gpg --verify "${REPODIR}/repodata/repomd.xml.asc" 2>&1 | sed -ne "s/.* ID //p")
    else
        gpg -a -b --default-key ${SIGN_ID} "${REPODIR}/repodata/repomd.xml"
    fi
    echo "INFO:    with Key-ID: ${SIGN_ID}"
    gpg -a --export ${SIGN_ID} > "${REPODIR}/repodata/repomd.xml.key"
fi
0707010000000A000081ED0000000000000000000000015C0E85F600000E21000000000000000000000000000000000000003400000000inst-source-utils-2018.12.10/usr/bin/create_sha1sum#!/bin/bash
#
# Copyright (C) 2008 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# $Id: create_sha1sum 1012 2013-02-17 10:49:03Z lrupp $
#

function usage (){
    echo
    echo "Usage: `basename $0` [--meta] <targetdir>"
    echo "       --meta : also create MD5SUMS.meta file"
    echo "       --quiet: don't output anything"
    echo 
    echo "       Creates SHA1SUMS files in each subdirectory."
    echo "       Sometimes useful for debugging inst-source problems ;-)"
    echo
    exit $1
}

function output(){
	if [ "$QUIET" != "yes" ]; then
		echo "$1"
	fi
}

unset LANGUAGE
unset LANG
export LC_ALL=POSIX
umask 022

CREATE_META=
QUIET="no"
CHECKSUM="sha1sum"
CHECKSUM_F="SHA1SUMS"

while test -n "$1" ; do
    case $1 in
	--) shift ; break ;;
        -h|--help) usage 0 ;;
	-m|--meta) CREATE_META=1 ; shift ;;
	-q|--quiet) QUIET="yes" ; shift ;;
	-2) CHECKSUM="sha256sum" ; CHECKSUM_F="CHECKSUMS" ; shift ;;
	*) break ;;
    esac
done
if [ -z "$1" ]; then
  usage 1;
fi

TMPFILE=$(mktemp /tmp/.create_sha1sums.XXXXXX)
MYPWD=$(pwd)

for ROOTDIR in "$@" ; do
    case "$ROOTDIR" in
	/*) ;;
	*) ROOTDIR="$MYPWD/$ROOTDIR" ;;
    esac

    test -d "$ROOTDIR" || {
        echo "WARNING: $ROOTDIR is not a directory.  Skipping it." >&2
    }

    find "$ROOTDIR" -type d | while read DIR; do
        cd "$DIR"
        unset FILES
        NFILES=0
        for FILE in * ; do
            test -f "$FILE" || continue
            test -L "$FILE" && continue
            test -n "$SHA1SUM_SKIPFILES" && {
                IS_SKIP=false
		        set -f
                for i in $SHA1SUM_SKIPFILES ; do
		          set +f
		          case "$FILE" in
			        ($i) IS_SKIP=true
			        break
			        ;;
		          esac
                done
		        set +f
                test $IS_SKIP = true && continue
            }
            case "$FILE" in
              (*.swp|SHA1SUMS*|CHECKSUMS*|MD5SUMS*)
                continue
                ;;
              (*)
                FILES[$[++NFILES]]="$FILE"
                ;;
            esac
          done
        if [ $NFILES -eq 0 ]; then
            rm -f SHA1SUMS* CHECKSUMS*
        else
            echo -n > $TMPFILE
            for FILE in "${FILES[@]}"; do
	            $CHECKSUM "$FILE" >> $TMPFILE
            done
            test -e $CHECKSUM_F || touch $CHECKSUM_F
	        cmp -s $TMPFILE $CHECKSUM_F || {
                mv $TMPFILE $CHECKSUM_F
				chmod 644 $CHECKSUM_F
                output "INFO:   created $CHECKSUM_F in $DIR"
	        }
        if test -n "$CREATE_META"; then
            test -e $CHECKSUM_F.meta || touch $CHECKSUM_F.meta
            $CHECKSUM $CHECKSUM_F > $TMPFILE
            cmp -s $TMPFILE $CHECKSUM_F.meta || {
		        mv $TMPFILE $CHECKSUM_F.meta
                chmod 644 $CHECKSUM_F.meta
                output "INFO:   created $CHECKSUM_F.meta in $DIR"
            }
	    fi
            rm -f $TMPFILE
        fi
    done
done
0707010000000B000081ED0000000000000000000000015C0E85F600001366000000000000000000000000000000000000003500000000inst-source-utils-2018.12.10/usr/bin/create_sha1sums#!/bin/bash
#
# Copyright (C) 2007 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License 2
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# $Id: create_sha1sums 1012 2013-02-17 10:49:03Z lrupp $
#

SIGN="yes"
SIGN_OPTS=""
INCLUDE_SHA1SUMS="no"
EXTRA="no"

CHECKSUM="sha1sum"
CHECKSUM_T="SHA1"
CHECKSUM_F="SHA1SUMS"
CHECKSUM_O=""

unset LANGUAGE
unset LANG
export LC_ALL=POSIX
umask 022

function usage() {
	echo "Usage: `basename $0` [OPTIONS] <CD-Rootdir>"
	echo "       -n : don't re-sign the generated files"
	echo "       -m : include SHA1SUMS files (or CHECKSUMS files for others)"
	echo "       -2 : use sha256 instead of sha1"
	echo "       -x : add sha1sums for extra files"
	echo
	echo "       (re-)creates the SHA*SUM lines in the content file"
	echo "       and signs the content and products file"
	exit $1
}

function signit(){
	if [ "$(type -p sign 2>/dev/null)" != "" ]; then 
#          if sign -t ; then
            sign $SIGN_OPTS -d $1
            sign $SIGN_OPTS -p > $1.key
#          else
#            : > $1.asc
#            cp //keys/default $1.key
#          fi
	else
	  gpg -a -b $1
	  KEY_ID=`gpg -b < /dev/null | gpg --list-packets | sed -n -e "/^:signature/s@.*keyid @@p"`
	  gpg --export --armor $KEY_ID > $1.key
	fi
}

while getopts 'hnmx2s:' OPTION ; do
	case $OPTION in
		h) usage 0
		;;
		m) INCLUDE_SHA1SUMS="yes"
		;;
		n) SIGN="no"
		;;
		s) SIGN_OPTS=$OPTARG
		;;
		x) EXTRA="yes"
		;;
		2)	CHECKSUM="sha256sum"
			CHECKSUM_T="SHA256"
			CHECKSUM_F="CHECKSUMS"
			CHECKSUM_O="-2"
		;;
	esac
done
shift $(( OPTIND - 1 ))

if [ ! "$1" ]; then
    usage 1
fi

CDS_PRIM=$1

if [ "$1" = "." ]; then
	CDS_PRIM=$(pwd)
fi

if [ -f $CDS_PRIM/content ] ; then
  # prepare content file
  CONTTMP=$(mktemp $CDS_PRIM/content-XXXXXX)
  grep -v "^META " $CDS_PRIM/content | grep -v "^KEY " | grep -v "^HASH SHA" > $CONTTMP
  mv $CONTTMP $CDS_PRIM/content
  
  # add pattern and packages files to content file
  DESCRDIR=`grep DESCRDIR $CDS_PRIM/content | awk '" " { print $2 }'`
  if [ -z "$DESCRDIR" ]; then
  	DESCRDIR="suse/setup/descr"
  fi
  if test -d $CDS_PRIM/$DESCRDIR ; then
    pushd $CDS_PRIM/$DESCRDIR >/dev/null
    rm -f *.asc
    $CHECKSUM * 2>/dev/null | grep -v "MD5SUMS" | grep -v "directory.yast" | sed -e "s@^@META $CHECKSUM_T @" >> $CDS_PRIM/content
    popd >/dev/null
  fi
  pushd $CDS_PRIM >/dev/null
  if [ "$EXTRA" = "yes" ] ; then
      for i in license.tar.gz control.xml installation.xml media.1/info.txt media.1/license.zip y2update.tgz driverupdate; do
          test -f $i || continue
          $CHECKSUM $i 2>/dev/null | sed -e "s@^@HASH $CHECKSUM_T @" >> $CDS_PRIM/content
      done
      for i in boot/*/* boot/*/loader/linux boot/*/loader/initrd boot/*/loader/*.spl docu/* images/* ; do
      	test -f $i || continue
          $CHECKSUM $i 2>/dev/null | sed -e "s@^@HASH $CHECKSUM_T @" >> $CDS_PRIM/content
      done
  	# check if we need to include additional files for > 11.0
  	if grep -q CONTENTSTYLE $CDS_PRIM/content; then
  		DATADIR=$(grep DATADIR content | awk '" " { print $2 }')
  		if [ -d "$CDS_PRIM/$DATADIR/setup/slide" ]; then
  			SLIDESHOWDIR="$CDS_PRIM/$DATADIR/setup/slide"
  		fi
  		if test -n "$SLIDESHOWDIR" -a -d "$SLIDESHOWDIR" ; then
  			/usr/bin/create_sha1sum $CHECKSUM_O --quiet "$SLIDESHOWDIR"
  		fi
  		if [ $SIGN = "yes" ]; then
  			for sha1sumfile in $(find $SLIDESHOWDIR -name $CHECKSUM_F); do
  				signit "$sha1sumfile"
  			done
  		fi
  	fi
  
  fi
  if [ "$INCLUDE_SHA1SUMS" = "yes" ]; then
      for i in $(find $CDS_PRIM/ -name $CHECKSUM_F | sed -e "s|./||"); do
          test -f $i || continue
          $CHECKSUM $i 2>/dev/null | sed -e "s@^@HASH $CHECKSUM_T @" >> $CDS_PRIM/content
      done
  fi
  
  # add gpg-key files to content file
  $CHECKSUM gpg-pubkey-* 2>/dev/null | sed -e "s@^@KEY $CHECKSUM_T  @" >> $CDS_PRIM/content
  popd >/dev/null
fi

# signing part
if [ $SIGN = "yes" ]; then
  REPOFILE=`find $CDS_PRIM -type f -name repomd.xml 2>/dev/null`
  REPOFILE=${REPOFILE##$CDS_PRIM}
  REPOFILE=${REPOFILE##/}
  for file in content media.1/products $REPOFILE; do
	test -f $CDS_PRIM/${file}.asc && rm -f $CDS_PRIM/${file}.asc
	test -f $CDS_PRIM/${file} || continue
	signit $CDS_PRIM/${file}
  done
fi

# make sure everything is readable for all
for file in content media.1/products $REPOFILE; do
	for xfile in $CDS_PRIM/$file* ; do
		test -e $xfile || continue
		chmod 644 $xfile
	done
done
0707010000000C000081ED0000000000000000000000015C0E85F6000014E0000000000000000000000000000000000000003D00000000inst-source-utils-2018.12.10/usr/bin/create_update_source.sh#!/bin/sh
#
# Copyright (C) 2006 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# This script creates an additional source in an existing tree to accomodate
# update packages without changing the original product tree.
# The script will only create the directory structure and the needed meta files.
#
# After running this script, you have to copy the packages into 
#
#		<source>/updates/suse/<arch>
#
# and run the script 
#
#	 	/usr/bin/create_package_descr -x setup/descr/EXTRA_PROV \
#
# in the data directory (<source>/updates/suse)
# after that do "cd setup/descr" and then:
# for i in *; do echo -n "META SHA1 "; sha1sum $i|awk '{ORS=""; print $1}'; echo -n " "; basename $i; done
# copy the output to the end of the updates/content file
#
#
# Anas Nashif
# Uwe Gansert (uwe.gansert@suse.de)
#
# Version 20060925 (uwe.gansert@suse.de)
#   - replaced =~ by grep to be compatible to pre bash 3.0
#
# Version 20060420 (uwe.gansert@suse.de)
#   - suppress META SHA1 lines in the content file
#
# Version 20060418 (uwe.gansert@suse.de)
#   - added support for add-on products of SLES10/SL10.1
#
# Version 20051207 (uwe.gansert@suse.de)
#   - added missing $SOURCE for the copy of the EXTRA_PROV file
#     thanx to Ian Grant
#

SOURCE=$1
ECHO=""
UPDATES="$SOURCE/updates"
NAME="Updates"

tmpcontent=`mktemp  /var/tmp/content-XXXXXX`

if [ -z "$SOURCE" ]; then
	echo
	echo "Argument missing, Provide the root of the installation source as"
	echo "the first argument"
	echo
	exit 1
fi

echo "Creating $UPDATES.."
if test -d $UPDATES ; then
	echo
	echo "$UPDATES already exists, aborting";
	echo
	exit 1
fi

function create_dy() {

	test -d $1 || return;

	for i in `ls $1` ; do
		case $i in
			*directory.yast)
			continue
		;;
		esac
		if test -d "$1/$i" ; then
			echo "$i/"
		else
			echo "$i"
		fi
	done > $1/directory.yast
}




if [ -f $SOURCE/content ] ; then
   while read KEY VALUE ; do
        case $KEY in
                DATADIR)
                        DATADIR=$VALUE
						echo $KEY $VALUE
                        ;;
                PRODUCT)
						echo $KEY $VALUE $NAME
                        ;;
                DESCRDIR)
                        DESCRDIR=$VALUE
						echo $KEY $VALUE
                        ;;
                DISTPRODUCT)
                        DISTPRODUCT=$VALUE
						echo "$KEY SuSE-Linux-Updates"
                        ;;
                DISTVERSION)
                        DISTVERSION=$VALUE
                        ;;
                META)
                        if [ -z "`echo -n $VALUE | grep SHA1`" ]; then
                            echo $KEY $VALUE
                        fi;
                        ;;
                ARCH.*)
                        if test -z "$ARCH"; then 
							ARCH=$VALUE
						fi
						echo $KEY $VALUE
                        ;;
				*)
						echo $KEY $VALUE
        esac
   done < $SOURCE/content > $tmpcontent


   DISTVERSION=`echo $DISTVERSION | tr '-' '#'`
   DISTIDENT="$DISTPRODUCT-$DISTVERSION"
   for i in $SOURCE/media.? ; do
      test -d $i || continue
      {
        read VENDOR
        read CREATIONDATE
      } < $i/media
   done
fi


$ECHO mkdir -p $UPDATES/$DATADIR
$ECHO mkdir -p $UPDATES/media.1
for arch in $ARCH; do 
	$ECHO mkdir -p $UPDATES/$DATADIR/$arch
done

$ECHO mkdir -p $UPDATES/$DESCRDIR

if [ -f "$SOURCE/$DESCRDIR/EXTRA_PROV" ]; then
	$ECHO cp $SOURCE/$DESCRDIR/EXTRA_PROV $UPDATES/$DESCRDIR
else
	echo "$DESCRDIR/EXTRA_PROV not found, trying to find it elsewhere..."
	find -name  EXTRA_PROV -exec cp {} $UPDATES/$DESCRDIR \;
fi


$ECHO mkdir -p $UPDATES/media.1
{
	echo "SuSE Linux AG"
	date +%Y%m%d%H%M%S
	echo 1
} > $UPDATES/media.1/media

{
    echo "/ $DISTPRODUCT-$NAME"
} > $UPDATES/media.1/products

if [ -x /usr/bin/create_package_descr ]; then
	create_package_descr -x $UPDATES/$DESCRDIR/EXTRA_PROV -d $UPDATES/$DATADIR \
					-o $UPDATES/$DESCRDIR
fi

(
	cd $UPDATES
        create_dy .
	for j in boot boot/loader $DESCRDIR media.1 ; do
    	create_dy $j
	done
	if [ -d $DESCRDIR/../slide ] ; then
    	for j in `find $DESCRDIR/../slide -type d ` ; do
        	create_dy $j
    	done
	fi
)


mkdir -p $SOURCE/yast


updates=`basename $UPDATES`
if [ -f "$SOURCE/yast/order" ]; then
	if grep -q $updates $SOURCE/yast/order ; then
		echo
		echo "order/instorder already in place, not touching them"
		echo
	else
		CREATE_ORDER=1
	fi
else
	CREATE_ORDER=1
fi


if [ "$CREATE_ORDER" = 1 ]; then
	echo "/$updates /$updates" >> $SOURCE/yast/order
	echo "/" >> $SOURCE/yast/order
	echo "/$updates" >> $SOURCE/yast/instorder
	echo  "/" >> $SOURCE/yast/instorder
fi


cp $tmpcontent $UPDATES/content
chmod a+r $UPDATES/content
rm -f $tmpcontent



0707010000000D000081ED0000000000000000000000015C0E85F60000AD6A000000000000000000000000000000000000003100000000inst-source-utils-2018.12.10/usr/bin/createpatch#!/usr/bin/perl
#
# Copyright (C) 2006 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# $Id: createpatch 186 2009-08-07 18:00:30Z lrupp $
#

BEGIN {
  $abuild_base_dir = "/usr/share/inst-source-utils";
  unshift @INC, "$abuild_base_dir/modules";
}

$| = 1;

use strict;
use Cwd;
use Data::Dumper;
use File::stat;
use File::Temp qw/ tempdir /;
use RPMQ;
use Time::localtime;
use Getopt::Long;

# cleanup the environment
$ENV{'PATH'}='/bin:/usr/bin:/sbin:/usr/sbin:';
$ENV{'BASH_ENV'}='';
$ENV{'ENV'}='';
$ENV{"LC_ALL"} = "C";
our $DEBUG=0;
our %config;
$config{'basedir'}           = cwd();
$config{'category'}          = "recommended";
$config{'do_signing'}        = 0;
$config{'do_susedata'}       = 0;
$config{'license_file'}      = "";
$config{'patch_name'}        = "usefirst";
$config{'patch_version'}     = 0;
$config{'patch_summary'}     = "";
$config{'patch_description'} = "";
$config{'sign_id'}           = "";
$config{'update_repo'}       = 0;
$config{'loglevel'}          = 7;
my $patch_id = `hostname -d`;
$config{'patch_id'}          = chomp($patch_id);

our %patchinfo_data=();
our $print_help="";
our $configfile="";
our @packagelist;
our @patchsupplements;
our @pkgrefresh;
our $LOCKFILE="/var/tmp/createpatch.lock";

###############################################################################
# Functions
###############################################################################

sub usage {
	my $exitcode=shift || 1;
       print <<EOF

$0 Usage Information:

 $0 [OPTION] ...

 -b <base_dir>          : is the base directory to the repository.

 -c <CONFIGFILE>        : file containing the option/values mentioned below
                          Notes: * use the fullnames as option
                                 * values in config file overwrite commandline 
                                   values!
 -e|--do_susedata       : create special susedata.xml files
 -i <PATCH_ID>          : Patch id, needs to be unique in world, will be prefixed
                          by "hostname -d" as default followed by the name of the
                          first package. Dots in "hostname -d" will be converted
                          to "_"s.
 -n <PATCH_NAME>        : required parameter, terse patch name, like aaa_base
 -v <PATCH_VERSION>     : default to "0"/first non-existant if not given
 -s <PATCH_SUMMARY>     : default to the package summary of the first RPM
                          specified on the command line
 -d <PATCH_DESCRTIPON>  : Long description, defaults to the package description
                          of the first RPM specified on commandline
 -C <CATEGORY>	        : Category for the patch.  Defaults to recommended.
                          Possible values: security, recommended, optional
 
 -u                     : run createrepo to update repository and take care of keeping
                          the patch*xml files - use when augmenting existing repository
                          with new patches.
 -s                     : Create special susedata.xml files  
 -S                     : detached sign the repomd.xml file
 -I <KEY_ID>            : key-id to use for signing the repomd.xml file, if not given
                          gpg will use the default signing key
 -L <CONFIRMATION_FILE> : add a confirmation request (EULA or Reboot request) to the patch, 
                          read from the file specified
 --validate             : use xmllint to validate the resulting xml file
 
 -p <rpm_basename>[,rpm_basename...]          : List of RPMs for this patch.
                                                You need at least one.
 --patchsupplements <PATCH_NAME>[,PATCH_NAME] : List of patches which are supplemented 
                                                by this patch
 --pkgfreshens rpm_basename                   : optional parameter which will override 
                                                the default freshens value
EOF
;

   exit $exitcode;
}

sub parsePrimaryXml ($) {
	my $data=shift;

	my @package_data;
	my %packdata;
	my $field = "package";
	my $lastfield = "package";

	# start extremely primitive xml parser ;)
	for (@$data){
      next if ( /^<\?xml/ );
	  for (split ('>',$_)) {
		$_ =~ s/^\s*(.*?)\s*$/$1/s;
		if ( /^<([^\ ]*)\ (.*)/ ) {
			$lastfield = $1;
			$field .= ".$lastfield";
			my $trail = $2;
			my $field_ends = 0;
			$field_ends = 1 if ( $trail =~ /\/$/ );
			$trail =~ s/\/$//;
			for (split('\ ',$trail)) {
				my ($key,$val) = split ('=',$_);
				$val =~ s/^\"(.*)\"$/$1/;
				$packdata{"$field.$key"} = $val;
				#print "'$field.$key' val = \"".$packdata{"$field.$key"}."\" (3)\n";
			}
			if ( $field_ends ) {
				if ( $field =~ /\./ ) {
					$field =~ s/\.[^\.]*$//;
					$lastfield = $field;
					$lastfield =~ s/^.*([^\.]*)$/$1/;
				} else {
					$field = "package";
					$lastfield = "package";
					if ($packdata{'package.name'}) {
						my %pack_data_tmp = %packdata;
						push @package_data, \%pack_data_tmp;
					}
					%packdata = ();
				}
			}
		} elsif ( /^<\/(.*)/ ) {
			if ( $field =~ /\./ ) {
				$field =~ s/\.[^\.]*$//;
				$lastfield = $field;
				$lastfield =~ s/^.*([^\.]*)$/$1/;
			} else {
				$field = "package";
				$lastfield = "package";
				if ($packdata{'package.name'}) {
					my %pack_data_tmp = %packdata;
					push @package_data, \%pack_data_tmp;
				}
				%packdata = ();
			}
		} elsif ( /^<([^\ >]*)/ ) {
		   my $tfield = $1;
		   if ( $tfield !~ /\/$/ ) {
				$field .= ".$tfield";
				$lastfield = $tfield;
		   }
		} elsif ( /^([^<]*)<\/$lastfield/ ) {
			$packdata{"$field"} = $1;
			#print "'$field' val = \"".$packdata{"$field"}."\" (2)\n";
			if ( $field =~ /\./ ) {
				$field =~ s/\.[^\.]*$//;
				$lastfield = $field;
				$lastfield =~ s/^.*([^\.]*)$/$1/;
			} else {
				$field = "package";
				$lastfield = "package";
				if ($packdata{'package.name'}) {
					my %pack_data_tmp = %packdata;
					push @package_data, \%pack_data_tmp;
				}
				%packdata = ();
			}
		} elsif ( /^(.*)=(.*)$/ ) {
		   my $key = $1;
		   my $val = $2;
		   $val =~ s/^\"(.*)\"$/$1/;
		   $packdata{"$field.$key"} = $val;
		   #print "'$field.$key' val = \"".$packdata{"$field.$key"}."\" lastfield = \"$lastfield\" (1)\n";
		} 
      }
	}
	# end extremely primitive xml parser ;)
	# for debugging only
	print "parsePrimaryXml: ".Dumper($package_data[0]) if ($DEBUG);
	return \@package_data;
}

sub updateRepo ($) {
	my $basedir=shift;
	my $res=0;
    my $savedir=tempdir( "createpatch-XXXXXX", TMPDIR => 1, CLEANUP => 1 );
	if (! -x '/usr/bin/createrepo'){
        warn "/usr/bin/createrepo not found or not executable.\n";
        warn "Please check if package createrepo is installed on your system.\n";
		return 1;
	}
	if ( opendir ( DIR, "$basedir")){
		for (readdir(DIR)) {
		    unlink "$basedir/repodata/$_" if ( /\.key$/ || /\.asc$/ );
		    next unless ( /^patch/ || /^product/ );
		    if ( /^patches.xml/ ) {
				unlink "$basedir/repodata/patches.xml";
				next;
		    }
		    link "$basedir/repodata/$_","$savedir/$_";
	    	unlink "$basedir/repodata/$_";
		}
		closedir (DIR);
	}
	$res=system("/usr/bin/createrepo -x \"*.patch.rpm\" -x \"*.delta.rpm\" $basedir 1>&2 2>/dev/null");
	print "createrepo: $res - by running /usr/bin/createrepo -x \"*.patch.rpm\" -x \"*.delta.rpm\" $basedir 1>&2 2>/dev/null\n" if ($DEBUG);
    if ( opendir ( DIR, "$savedir" ) ) {
		for (readdir(DIR)) {
	    	link "$savedir/$_","$basedir/repodata/$_";
		    unlink "$savedir/$_";
		}
		closedir (DIR);
    }
	return $res;
}

sub GeneratePatchesXml($) {
    my ($patches_directory) = @_;

    opendir(PDIR,"$patches_directory");
    my @all_patches = grep {/^patch-.*\.xml$/} readdir(PDIR);
    closedir(PDIR);

    if (@all_patches) {
        open (NEWDIR,">$patches_directory/patches.xml");
        print NEWDIR "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        print NEWDIR "<patches xmlns=\"http://novell.com/package/metadata/suse/patches\">\n";
        my $pdirname = $patches_directory;
        $pdirname =~ s/^.*\///;
        for my $current_patch (@all_patches) {
            my ($checksum,$dummy) = split('\s+',`sha1sum "$patches_directory/$current_patch"`);
            my $category = "";
            if ($patches_directory =~ /\/you/) {
                open(PATCH,"$patches_directory/$current_patch");
                my @TMP = <PATCH>;
                close(PATCH);
                chomp(@TMP);
                $category = (grep { /<category>/ } @TMP)[0];
                if ($category) {
                $category =~ s/^\s+//;
                $category =~ s/\s+$//;
                $category = "    $category\n";
                }
                LOG("$current_patch: $category",7);
            }
            $current_patch =~ s/.xml$//;
            my $name = $current_patch;
            $name =~ s/^patch-//;
            print NEWDIR "  <patch id=\"$name\">\n";
            print NEWDIR "    <checksum type=\"sha\">$checksum</checksum>\n";
            print NEWDIR "    <location href=\"$pdirname/$current_patch.xml\"/>\n$category";
            print NEWDIR "  </patch>\n";
        }
        print NEWDIR "</patches>\n";
        close (NEWDIR);
    } else {
        LOG("GeneratePatchesXml: no patches found, removing patches.xml",3);
        unlink "$patches_directory/patches.xml";
    }
}

sub GenerateRepomdXml($) {
    my ($patches_directory) = @_;
    opendir(PDIR,"$patches_directory");
    my @all_patches = grep {/\.xml(\.gz)?$/} readdir(PDIR);
    closedir(PDIR);
    open (NEWDIR,">$patches_directory/repomd.xml");
    print NEWDIR "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    print NEWDIR "<repomd xmlns=\"http://linux.duke.edu/metadata/repo\">\n";
    my $pdirname = $patches_directory;
    $pdirname =~ s/^.*\///;
    for (@all_patches) {
        next if (/^patch-/);
        next if (/^repomd/);
        my ($checksum,$dummy) = split('\s+',`sha1sum "$patches_directory/$_"`);
        my $o_checksum = $checksum;
        if ( /\.gz/ ) {
            ($o_checksum,my $dummy) = split('\s+',`gzip -dc "$patches_directory/$_" | sha1sum`);
        }
        my $timestamp = stat("$patches_directory/$_")->mtime;
        my $filename = $_;
        $_ =~ s/.xml(\.gz)?$//;
        print NEWDIR "  <data type=\"$_\">\n";
        print NEWDIR "    <location href=\"$pdirname/$filename\"/>\n";
        print NEWDIR "    <checksum type=\"sha\">$checksum</checksum>\n";
        print NEWDIR "    <timestamp>$timestamp</timestamp>\n";
        print NEWDIR "    <open-checksum type=\"sha\">$o_checksum</open-checksum>\n";
        print NEWDIR "  </data>\n";
    }
    print NEWDIR "</repomd>\n";
    close ( NEWDIR );
}

sub xml_escape($) {
    my ($text) = @_;
    $text =~ s/&/&amp;/sg;
    $text =~ s/</&lt;/sg;
    $text =~ s/>/&gt;/sg;
    $text =~ s/"/&quot;/sg;
    #$text =~ s/([\x80-\xff])/$1 lt "\xC0" ? "\xC2$1" : "\xC3".chr(ord($1)-64)/ge;
    return $text;
}

# poor mans utf8 converter
sub to_xml_utf8 {
	my ($in_text) = @_;
    my $text = xml_escape($in_text);
    $text =~ s/([\x80-\xff])/$1 lt "\xC0" ? "\xC2$1" : "\xC3".chr(ord($1)-64)/ge;
    return $text;
}

sub trim($){
	my $string = shift;
	$string =~ s/^\s*//;
	$string =~ s/\s*$//;
	return $string;
}

sub ParseConfig($) {
	my $conf = shift;
	my %config;
	open(CONF,"$conf") or die ("Could not open $conf: $!\n");
	while (<CONF>){
		next if (/^#/);
		next if /^\s*$/;

		my ($tag, $data);
		if (/=/){
			($tag,$data)=split(/\s*=\s*/, $_, 2);
			$tag=trim($tag);
			$data=trim($data);
		} elsif (/:/){
			($tag,$data) = split(/\s*:\s*/, $_, 2);
			$tag=trim($tag);
            $data=trim($data);
		} elsif (/ /){
			($tag, $data) = split(/\s*/, $_, 2);
			$tag=trim($tag);
			$data=trim($data);
		}
		$config{$tag}="$data";
	}
	close(CONF);
	return \%config;
}

sub writePatchFile($$$) {
  my $configref=shift;
  my $repodata=shift;
  my $package_dataref=shift;
  my %config=%$configref;
  my @package_data=@$package_dataref;

  if ($#packagelist ge 0) {
    my $timestamp = time;
    my $iteration = $config{'patch_version'};
    while ( -f "$repodata/patch-$config{'patch_id'}-$config{'patch_name'}-$iteration.xml" ) {
		warn ("patch-$config{'patch_id'}-$config{'patch_name'}-$iteration.xml does already exist, increasing version\n");
		$iteration++;
    }

    # patch header, mostly static
    my $patch_text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    $patch_text .= "<patch\n    xmlns=\"http://novell.com/package/metadata/suse/patch\"\n";
    $patch_text .= "    xmlns:yum=\"http://linux.duke.edu/metadata/common\"\n";
    $patch_text .= "    xmlns:rpm=\"http://linux.duke.edu/metadata/rpm\"\n";
    $patch_text .= "    xmlns:suse=\"http://novell.com/package/metadata/suse/common\"\n";
    $patch_text .= "    patchid=\"$config{'patch_id'}-$config{'patch_name'}-$iteration\"\n    timestamp=\"$timestamp\"\n    engine=\"1.0\">\n";
    $patch_text .= "  <yum:name>$config{'patch_id'}-$config{'patch_name'}</yum:name>\n";
    $patch_text .= "  <summary lang=\"en\">".xml_escape($config{'patch_summary'})."</summary>\n";
    $patch_text .= "  <description lang=\"en\">".xml_escape($config{'patch_description'})."</description>\n";
    $patch_text .= "  <yum:version ver=\"$iteration\" rel=\"0\"/>\n";
    $patch_text .= "  <rpm:requires>\n";

    my %seen_already;
    for (@package_data) {
	    # this package wanted in patch ?
    	my $pack_name = $_->{'package.name'};
	    my $long_name = $_->{'package.location.href'};
	    $long_name =~ s/^.*\/([^\/]*)/$1/;
    	next unless grep { $_ eq $pack_name || $_ eq $long_name } @packagelist;

    	# duplicate filter
	    next if ( $seen_already{"$_->{'package.name'}-$_->{'package.version.epoch'}-$_->{'package.version.ver'}-$_->{'package.version.rel'}"} );
    	$seen_already{"$_->{'package.name'}-$_->{'package.version.epoch'}-$_->{'package.version.ver'}-$_->{'package.version.rel'}"} = 1;

    	# make the patch require the atom associated with this package
	    $patch_text .= "    <rpm:entry kind=\"atom\" name=\"$_->{'package.name'}\"";
        $patch_text .= " epoch=\"$_->{'package.version.epoch'}\"";
        $patch_text .= " ver=\"$_->{'package.version.ver'}\"";
        $patch_text .= " rel=\"$_->{'package.version.rel'}\" flags=\"EQ\"/>\n";
    }
    $patch_text .= "  </rpm:requires>\n";

    # do we have any supplements tags at all
    if ($#patchsupplements ge 0){
		$patch_text .= "  <rpm:supplements>\n";
		for (@patchsupplements){
			$patch_text .= "    <rpm:entry kind=\"patch\" name=\"$_\"/>\n";
		}
		$patch_text .= "  </rpm:supplements>\n";
    }

    $patch_text .="  <category>$config{'category'}</category>\n";

    if ( $config{'license_file'} && -f "$config{'license_file'}" ) {
		$patch_text .= "  <license-to-confirm>\n";
		open ( LIC, "< $config{'license_file'}");
		while ( <LIC> ) {
		    $patch_text .= xml_escape($_);
		}
		close ( LIC );
		$patch_text .= "  </license-to-confirm>\n";
    }
    $patch_text .= "  <atoms>\n";

    for (@package_data) {
		# this package wanted in patch ?
		my $pack_name = $_->{'package.name'};
		my $long_name = $_->{'package.location.href'};
		my $freshens;
		$long_name =~ s/^.*\/([^\/]*)/$1/;
		next unless grep { $_ eq $pack_name || $_ eq $long_name } @packagelist;
		# create atom data, mostly just copies from primary package data
		$patch_text .= "    <package xmlns=\"http://linux.duke.edu/metadata/common\" type=\"rpm\">\n";
		$patch_text .= "      <name>$_->{'package.name'}</name>\n";
		$patch_text .= "      <arch>$_->{'package.arch'}</arch>\n";
		$patch_text .= "      <version epoch=\"$_->{'package.version.epoch'}\" ver=\"$_->{'package.version.ver'}\" rel=\"$_->{'package.version.rel'}\"/>\n";
		$patch_text .= "      <checksum type=\"sha\" pkgid=\"YES\">$_->{'package.checksum'}</checksum>\n";
		$patch_text .= "      <time file=\"$_->{'package.time.file'}\" build=\"$_->{'package.time.build'}\"/>\n";
		$patch_text .= "      <size package=\"$_->{'package.size.package'}\" installed=\"$_->{'package.size.installed'}\" archive=\"$_->{'package.size.archive'}\"/>\n";
		$patch_text .= "      <location href=\"$_->{'package.location.href'}\"/>\n";
		# here starts the association of the atom to the real package
		$patch_text .= "      <format>\n        <rpm:requires>\n";
		$patch_text .= "          <rpm:entry kind=\"package\"";
		$patch_text .= " name=\"$_->{'package.name'}\"";
		$patch_text .= " epoch=\"$_->{'package.version.epoch'}\"";
		$patch_text .= " ver=\"$_->{'package.version.ver'}\"";
		$patch_text .= " rel=\"$_->{'package.version.rel'}\"";
		$patch_text .= " flags=\"GE\"/>\n";
		$patch_text .= "        </rpm:requires>\n";
		# now have the atom pulled in, if this package is installed on the system
		$patch_text .= "        <suse:freshens>\n";
		# do we need to override the freshens tag
		if ($#pkgrefresh ge 0){
			for(@pkgrefresh){
				$patch_text .= "          <suse:entry kind=\"package\" name=\"$_\"/>\n";
			}
		}
		else{
			$patch_text .= "          <suse:entry kind=\"package\" name=\"$_->{'package.name'}\"/>\n";
		}
		$patch_text .= "        </suse:freshens>\n      </format>\n    </package>\n";
    }

    $patch_text .= "  </atoms>\n</patch>\n";
    open ( PATCH, "> $repodata/patch-$config{'patch_id'}-$config{'patch_name'}-$iteration.xml");
    print PATCH $patch_text;
    close ( PATCH );
  }
}

#
# write out the xml file and gzip it, atomic
#
sub UpdateXmlFile {
    my ($patches_directory,$xname,$data) = @_;
    open ( PRIMARY, "| gzip > $patches_directory/$xname.xml.gz.new");
    print PRIMARY "$data->{header}\n";
    # actually faster this way according to testing
    for (@{$data->{newdata}}) {
        print PRIMARY "$_\n" if defined $_;
    }
    print PRIMARY "$data->{footer}\n";
    close ( PRIMARY );
    rename ( "$patches_directory/$xname.xml.gz.new", "$patches_directory/$xname.xml.gz");
    unlink ("$patches_directory/$xname.xml") if ( -f "$patches_directory/$xname.xml" );
}

#
# extremely primitive xml input: split records at "<package "
#
sub ReadXmlFile {
    my ($patches_directory,$xname,$dataname) = @_;
    my @PRIMARY;

    if ( -f "$patches_directory/$xname.xml.gz" ) {
        open ( PRIMARY, "zcat $patches_directory/$xname.xml.gz |");
    } else {
        open ( PRIMARY, "$patches_directory/$xname.xml");
    }
    {
        local $/ = "<package ";
        @PRIMARY = <PRIMARY>;
        chomp (@PRIMARY);
    }
    close ( PRIMARY );

    unless ( $PRIMARY[1] ) {
        $PRIMARY[0] =~ s/<\/$dataname>//g;
        push @PRIMARY, "nil></package>\n</$dataname>";
    }
    my $header_primary = shift(@PRIMARY);
    $header_primary =~ s/^\s*(.*?)\s*$/$1/s;

    my $footer_primary = $PRIMARY[$#PRIMARY];
    $PRIMARY[$#PRIMARY] =~ s/<\/package\>.*$/<\/package\>/s;
    $footer_primary =~ s/^.*<\/package>//s;
    $footer_primary =~ s/^\s*(.*?)\s*$/$1/s;

    return ($header_primary,$footer_primary,\@PRIMARY);
}

sub cleanup(){
	unlink "$LOCKFILE" if ( -f "$LOCKFILE");
}

# simple logfile writer
sub LOG {
	my $entry = shift;
	my $level = shift || 1;
	my $xtime=`date`;
	chomp($xtime);
	if ( $level lt $config{'loglevel'} ){
		print OUTPUT_LOG "$xtime: $entry\n";
	}
	print "$xtime: $entry\n" if ($DEBUG);
}

#
# helper functions for GetPackageDataFromRpm
#
# only weak deps (enhances, suggests)
sub filter_weak {
    my ($tn, $tf) = @_;
    my @tf = @{$tf || []};
    my @res;
    for (@{$tn || []}) {
        push @res, $_ unless (shift @tf) & 0x8000000;
    }
    return @res;
}

# only strong ones (recommends, supplements)
sub filter_strong {
    my ($tn, $tf) = @_;
    my @tf = @{$tf || []};
    my @res;
    for (@{$tn || []}) {
        push @res, $_ if (shift @tf) & 0x8000000;
    }
    return @res;
}

# combine deps and their relations and flags
sub add_flagsvers_special {
    my $res = shift;
    my $name = shift;
    my $flags = shift;
    my $vers = shift;
    my $filter = shift;

    my @raw_dep_names = @{$res->{$name} || []};
    my @raw_dep_flags = @{$res->{$flags} || []};
    my @raw_dep_vers = @{$res->{$vers} || []};
    if ($filter && @raw_dep_flags) {
        @raw_dep_names = $filter->(\@raw_dep_names, \@raw_dep_flags);
        @raw_dep_vers  = $filter->(\@raw_dep_vers,  \@raw_dep_flags);
        @raw_dep_flags = $filter->(\@raw_dep_flags, \@raw_dep_flags);
    }
    my @raw_provides = ();
    for (@raw_dep_names) {
        my %prov_line = ();
        $prov_line{'name'} = $_;
        my ($epoch, $version) = $raw_dep_vers[0] =~ /^(?:(\d+):)?(.*?)$/;
        my $release = '';
        ($version, $release) = ($1, $2) if $version =~ /^(.*)-(.*?)$/;
        $prov_line{'epoch'} = $epoch;
        $prov_line{'ver'} = $version;
        $prov_line{'rel'} = $release;
        if (@raw_dep_flags && ($raw_dep_flags[0] & 0xe) && @raw_dep_vers) {
            my @rels = qw{FALSE FALSE LT LT GT GT NE NE EQ EQ LE LE GE GE TRUE TRUE};
            $prov_line{'flags'} = $rels[$raw_dep_flags[0] & 0xe];
        }
        if (@raw_dep_flags  && $raw_dep_flags[0] & 64) {
            $prov_line{'pre'} = 1;
        }
        shift @raw_dep_flags;
        shift @raw_dep_vers;
        push @raw_provides, \%prov_line;
    }
    return \@raw_provides;
}

# find out all about the given package
sub GetPackageDataFromRpm {
    my ($package_file) = @_;
    my %package_data = ();
    my $dummy = "";
    $package_data{"fullpath"} = $package_file;
    $package_file =~ /.*\/([^\/]*)$/;
    $package_data{"basename"} = $1;
    $package_data{"filesize"} = stat($package_file)->size;
    $package_data{"filetime"} = stat($package_file)->mtime;
    ($package_data{"checksum_sha"},$dummy) = split('\s+',`sha1sum $package_file`);
    my %res = RPMQ::rpmq_many($package_file,'NAME','EPOCH','VERSION','RELEASE','SIZE','BUILDTIME','GROUP','ARCH','LICENSE',
                                'SOURCERPM','PROVIDENAME','PROVIDEFLAGS','PROVIDEVERSION',
                                'REQUIRENAME','REQUIREFLAGS','REQUIREVERSION',
                                'CONFLICTNAME','CONFLICTFLAGS','CONFLICTVERSION',
                                'OBSOLETENAME','OBSOLETEFLAGS','OBSOLETEVERSION',
                                'SUGGESTSNAME','SUGGESTSFLAGS','SUGGESTSVERSION',
                                'ENHANCESNAME','ENHANCESFLAGS','ENHANCESVERSION',
                                'FILENAMES','FILEMODES','SUMMARY','DESCRIPTION','HEADERSTART','HEADEREND',
                                'CHANGELOGTIME','CHANGELOGNAME','CHANGELOGTEXT','PACKAGER','VENDOR','URL',
                                'ARCHIVESIZE','SIGTAG_PAYLOADSIZE','BUILDHOST');
    $package_data{"name"} = ($res{'NAME'} || [])->[0];
    $package_data{"epoch"} = ($res{'EPOCH'} || [])->[0];
    $package_data{"epoch"} = "0" unless ($package_data{"epoch"});
    $package_data{"version_only"} = ($res{'VERSION'} || [])->[0];
    $package_data{"release"} = ($res{'RELEASE'} || [])->[0];
    $package_data{"version"} = "$package_data{version_only}-$package_data{release}";
    $package_data{"rpmsize"} = ($res{'SIZE'} || [])->[0];
    $package_data{"archivesize"} = ($res{'ARCHIVESIZE'} || [])->[0];
    $package_data{"archivesize"} = ($res{'SIGTAG_PAYLOADSIZE'} || [])->[0] unless ($package_data{"archivesize"});
    $package_data{"buildtime"} = ($res{'BUILDTIME'} || [])->[0];
    $package_data{"rpmgroup"} = ($res{'GROUP'} || [])->[0];
    $package_data{"rpmarch"} = ($res{'ARCH'} || [])->[0];
    $package_data{"license"} = ($res{'LICENSE'} || [])->[0];
    $package_data{"sourcerpm"} = ($res{'SOURCERPM'} || [])->[0];
    $package_data{"packager"} = ($res{'PACKAGER'} || [])->[0];
    $package_data{"vendor"} = ($res{'VENDOR'} || [])->[0];
    $package_data{"url"} = ($res{'URL'} || [])->[0];
    $package_data{"rpmarch"} = "src" unless ( $package_data{"sourcerpm"} );
    $package_data{"headerstart"} = $res{'HEADERSTART'};
    $package_data{"headerend"} = $res{'HEADEREND'};
    $package_data{"summary"} = ($res{'SUMMARY'} || [])->[0];
    $package_data{"buildhost"} = ($res{'BUILDHOST'} || [])->[0];
    $package_data{"description"} = join(' ',@{$res{'DESCRIPTION'}});
    my @dirs = ();
    my @files = ();
    for (@{$res{'FILENAMES'}}) {
    if ( @{$res{'FILEMODES'}}[0] & 0040000 ) {
        push @dirs, $_;
    } else {
        push @files, $_;
    }
    shift @{$res{FILEMODES}}
    }
    $package_data{"rpmlistdirs"} = \@dirs;
    $package_data{"rpmlistfiles"} = \@files;
    # raw deps
	$package_data{"providesraw"} = add_flagsvers_special(\%res,'PROVIDENAME','PROVIDEFLAGS','PROVIDEVERSION');
    $package_data{"requiresraw"} = add_flagsvers_special(\%res,'REQUIRENAME','REQUIREFLAGS','REQUIREVERSION');
    $package_data{"conflictsraw"} = add_flagsvers_special(\%res,'CONFLICTNAME','CONFLICTFLAGS','CONFLICTVERSION');
    $package_data{"obsoletesraw"} = add_flagsvers_special(\%res,'OBSOLETENAME','OBSOLETEFLAGS','OBSOLETEVERSION');
    $package_data{"supplementsraw"} = add_flagsvers_special(\%res,'ENHANCESNAME','ENHANCESFLAGS','ENHANCESVERSION', \&filter_strong);
    $package_data{"enhancesraw"} = add_flagsvers_special(\%res,'ENHANCESNAME','ENHANCESFLAGS','ENHANCESVERSION', \&filter_weak);
    $package_data{"recommendsraw"} = add_flagsvers_special(\%res,'SUGGESTSNAME','SUGGESTSFLAGS','SUGGESTSVERSION', \&filter_strong);
    $package_data{"suggestsraw"} = add_flagsvers_special(\%res,'SUGGESTSNAME','SUGGESTSFLAGS','SUGGESTSVERSION', \&filter_weak);

    # cooked deps
    RPMQ::rpmq_add_flagsvers(\%res,'PROVIDENAME','PROVIDEFLAGS','PROVIDEVERSION');
    RPMQ::rpmq_add_flagsvers(\%res,'REQUIRENAME','REQUIREFLAGS','REQUIREVERSION');
    $package_data{"provides"} = join(' ',@{$res{'PROVIDENAME'}});
    $package_data{"requires"} = join(' ',@{$res{'REQUIRENAME'}});
    $package_data{"provides"} =~ s/\s+/ /g;
    $package_data{"provides"} =~ s/\s+$//g;
    $package_data{"requires"} =~ s/\s+/ /g;
    $package_data{"requires"} =~ s/\s+$//g;
    $package_data{"changelogtime"} = $res{'CHANGELOGTIME'};
    $package_data{"changelogname"} = $res{'CHANGELOGNAME'};
    $package_data{"changelogname"} =~ s/^- //;
    $package_data{"changelogtext"} = $res{'CHANGELOGTEXT'};
    return %package_data;
}


sub ReadFileToHash($){
	my $file=shift;
	my %temp;
	open(FILE,"< $file") or return undef;
	while (<FILE>){
		chomp;
		last if $_ =~ /^:END/ ;
	    next if ( $_ =~ /^\#/ );
    	next if ( $_ =~ /^\s$/ );
		my ($le,$ri) = split (/:/,$_,2);
		$le=trim($le);
		$ri=trim($ri);
		$ri=~ s/\\n/\n/g;
		$temp{$le}=$ri;
	}	
	close(FILE);
	return \%temp;
}	

#
# create package information in xml format as given for repomd
#
sub PackageDataToXML {
my ($curpack) = @_;
    my $boilerplate .= "    <package xmlns=\"http://linux.duke.edu/metadata/common\" type=\"rpm\">\n";
    my $header = "      <name>".$curpack->{"name"}."</name>\n";
    $header .= "      <arch>".$curpack->{"rpmarch"}."</arch>\n";
    $header .= "      <version epoch=\"$curpack->{epoch}\" ver=\"$curpack->{version_only}\" rel=\"$curpack->{release}\"/>\n";
    $header .= "      <checksum type=\"sha\" pkgid=\"YES\">".$curpack->{"checksum_sha"}."</checksum>\n";
    $header .= "      <summary lang=\"en\">".to_xml_utf8($curpack->{summary})."</summary>\n";
    $header .= "      <description lang=\"en\">".to_xml_utf8($curpack->{description})."</description>\n";
    $header .= "      <packager>$curpack->{packager}</packager>\n";
    $header .= "      <url>".to_xml_utf8($curpack->{url})."</url>\n";
    $header .= "      <time file=\"$curpack->{filetime}\" build=\"$curpack->{buildtime}\"/>\n";
    $header .= "      <size package=\"$curpack->{filesize}\" installed=\"$curpack->{rpmsize}\" archive=\"$curpack->{archivesize}\"/>\n";
    $header .= "      <location href=\"rpm/$curpack->{rpmarch}/$curpack->{basename}\"/>\n";

    #
    ## FORMAT START
    #
    my $data = "        <rpm:license>$curpack->{license}</rpm:license>\n";
    $data .= "        <rpm:vendor>$curpack->{vendor}</rpm:vendor>\n";
    $data .= "        <rpm:group>$curpack->{rpmgroup}</rpm:group>\n";
    $data .= "        <rpm:buildhost>$curpack->{buildhost}</rpm:buildhost>\n";
    if ( $curpack->{sourcerpm} ) {
        $data .= "        <rpm:sourcerpm>$curpack->{sourcerpm}</rpm:sourcerpm>\n";
    } else {
        $data .= "        <rpm:sourcerpm/>\n";
    }
    $data .= "        <rpm:header-range start=\"$curpack->{headerstart}\" end=\"$curpack->{headerend}\"/>\n";
    for my $dep_type (qw{provides requires conflicts obsoletes suggests enhances recommends supplements}) {
    my $dep_list = $curpack->{"${dep_type}raw"};
    if ($dep_list && @$dep_list) {
        $data .= "        <rpm:$dep_type>\n";
        for my $dep_data (@$dep_list) {
            $data .= "          <rpm:entry";
            # name,epoch,ver,rel,pre,flags
            for (qw{name flags epoch ver rel pre}) {
                $data .= " $_=\"$dep_data->{$_}\"" if defined ($dep_data->{$_}) && $dep_data->{$_} ne "";
            }
            $data .= "/>\n";
        }
        $data .= "        </rpm:$dep_type>\n";
    }
    }
    for (grep {/.*bin\/.*/ || /^\/etc\/.*/} @{$curpack->{rpmlistdirs}} ) {
        $data .= "        <file type=\"dir\">$_</file>\n";
    }
    for (grep {/.*bin\/.*/ || /^\/usr\/lib\/sendmail$/ || /^\/etc\/.*/} @{$curpack->{rpmlistfiles}} ) {
        $data .= "        <file>$_</file>\n";
    }
    #
    ## FORMAT END
    #
    my $filelist = "";
    for (@{$curpack->{rpmlistdirs}}) {
        $filelist .= "        <file type=\"dir\">".to_xml_utf8($_)."</file>\n";
    }
    for (@{$curpack->{rpmlistfiles}}) {
        $filelist .= "        <file>".to_xml_utf8($_)."</file>\n";
    }
    return ($boilerplate , $header, $data, $filelist);
}

#
# regenerate the updateinfo.xml.gz file: scan all updateinfo-foo.xml and include literally
#
sub GenerateUpdateinfoXml {
    my ($patches_directory) = @_;

    opendir(PDIR,"$patches_directory/../repoparts");
    my @all_files = readdir(PDIR);
    my @all_patches = grep {/^updateinfo-.*\.xml$/} @all_files;
    my @all_deltas = grep {/^deltainfo-.*\.xml$/} @all_files;
    closedir(PDIR);

    if (@all_patches) {
        # concat for updateinfo
        open (NEWDIR,"| gzip > $patches_directory/updateinfo.xml.gz.new");
        print NEWDIR "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        print NEWDIR "<updates xmlns=\"http://novell.com/package/metadata/suse/updateinfo\">\n";
        for my $current_patch (@all_patches) {
            open (PATCH, "< $patches_directory/../repoparts/$current_patch");
            print NEWDIR join('',grep {$_ !~ /^<.xml version/} <PATCH>);
            close (PATCH);
        }
        print NEWDIR "</updates>\n";
        close (NEWDIR);
        my $xname = "updateinfo";
        rename ( "$patches_directory/$xname.xml.gz.new", "$patches_directory/$xname.xml.gz");
        unlink ("$patches_directory/$xname.xml") if ( -f "$patches_directory/$xname.xml" );
        # concat for deltainfo
        open (NEWDIR,"| gzip > $patches_directory/deltainfo.xml.gz.new");
        print NEWDIR "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        print NEWDIR "<deltainfo>\n";
        for my $current_delta (@all_deltas) {
            open (PATCH, "< $patches_directory/../repoparts/$current_delta");
            print NEWDIR join('',grep {$_ !~ /^<.xml version/} <PATCH>);
            close (PATCH);
        }
        print NEWDIR "</deltainfo>\n";
        close (NEWDIR);
        $xname = "deltainfo";
        rename ( "$patches_directory/$xname.xml.gz.new", "$patches_directory/$xname.xml.gz");
        unlink ("$patches_directory/$xname.xml") if ( -f "$patches_directory/$xname.xml" );
        unlink ("$patches_directory/patches.xml") if ( -f "$patches_directory/patches.xml" );
    } else {
        LOG ("GenerateUpdateinfoXml: no updates found, removing updateinfo.xml",2);
        unlink "$patches_directory/updateinfo.xml";
        unlink "$patches_directory/updateinfo.xml.gz";
    }
}

###############################################################################
# Main
###############################################################################
Getopt::Long::Configure('bundling');

GetOptions(
    'h|help' => \$print_help,
    'b|basedir=s' => \$config{'basedir'},
    'c|configfile=s' => \$configfile,
	'C|category=s' => \$config{'category'},
	'e|do_susedata' => \$config{'do_susedata'},
	'i|patch_id=s' => \$config{'patch_id'},
    'l|logfile=s'  => \$config{'logfile'},
    'k|keywordfile=s' => \$config{'keywordfile'},
	'n|patch_name=s' => \$config{'patch_name'},
	'v|patch_version=i' => \$config{'patch_version'},
	's|patch_summary=s' => \$config{'patch_summary'},
	'd|patch_description=s' => \$config{'patch_description'},
	'u|update_repo' => \$config{'update_repo'},
	'S|do_signing' => \$config{'do_signing'},
	'I|sign_id=s' => \$config{'sign_id'},
	'L|license_file=s' => \$config{'license_file'},
	'p|packagelist=s' => \@packagelist,
	'patchsupplements=s' => \@patchsupplements,
	'pkgfreshens=s' => \@pkgrefresh,
);

usage(0) if ($print_help);

if ("$configfile" ne ""){
	if (-r "$configfile"){
		my $configref=ParseConfig("$configfile");
        %config=%$configref;
	} else {
		die ("Could not open $configfile\n");
	}
}
$config{'patch_id'} =~ s/\./_/g;

#die ("Lockfile ($LOCKFILE) already exists at ".ctime()."\n") if (-f "$LOCKFILE");
#open (LOCK,">$LOCKFILE") || die "Cannot write lockfile $LOCKFILE : $!\n";
#print LOCK "$$\n";
#close(LOCK);

$::SIG{"__DIE__"} = sub {
    die (@_) if $^S;
    \&cleanup;
};

open ( OUTPUT_LOG , ">>$config{'logfile'}");
select (OUTPUT_LOG); $| = 1; select (STDOUT);

my $repodata = "$config{'basedir'}/repodata";
my $first_package = "";

if ( @packagelist && $packagelist[0] ){
	$first_package = $packagelist[0];
	@packagelist=split(/,/,join(',',@packagelist));
}
@patchsupplements=split(/,/,join(',',@patchsupplements)) if ( @patchsupplements );
@pkgrefresh=split(/,/,join(',',@pkgrefresh)) if (@pkgrefresh);

if ( $config{'patch_name'} eq "usefirst" ) {
    $config{'patch_name'} = "$first_package" if ( "$first_package" );
}

if ($DEBUG){
	print "config: ".Data::Dumper->Dump([\%config]);
	for (@patchsupplements){
		print "patchsupplements : $_\n";
	}
	for (@pkgrefresh){
		print "pkgrefresh       : $_\n";
	}
	for (@packagelist){
		print "packagelist      : $_\n";
	}
}

LOG("Start creation for $repodata",1);
my $res=updateRepo("$config{'basedir'}") if ($config{'update_repo'});
die "Could not update the Repository\n" if ($res);

if ( -f "$repodata/primary.xml.gz" ) {
    open ( PRIMARY, "zcat $repodata/primary.xml.gz |") || warn ("Could not open primary.xml.gz : $!\n");
} else {
    open ( PRIMARY, "$repodata/primary.xml") || warn ("Could not open primary.xml : $!\n");
}

my @PRIMARY;
{
    local $/ = "<package ";
    @PRIMARY = <PRIMARY>;
    chomp (@PRIMARY);
}
close ( PRIMARY );

my $package_dataref=parsePrimaryXml(\@PRIMARY);
my @package_data=@$package_dataref;

for (@package_data) {
    my $pack_name = $_->{'package.name'};
    my $long_name = $_->{'package.location.href'};
    $long_name =~ s/^.*\/([^\/]*)/$1/;
    next unless ( $pack_name eq $first_package || $long_name eq $first_package );
    # primitive approach: use summary and description of the first package found
    $config{'patch_summary'} = $_->{'package.summary'} unless ($config{'patch_summary'});
    $config{'patch_description'} = $_->{'package.description'} unless ($config{'patch_description'});
}

if ($config{'do_susedata'}){
	my %xfiles = (  'susedata' => 'susedata',
					'primary'  => 'metadata',
					'filelists' => 'filelists',
					'other'    => 'otherdata',
				  );
	our %data;
	for my $name (sort(keys %xfiles)){
		my $tag = $xfiles{$name};
		if ( ! -f "$repodata/$name.xml.gz" && ! -f "$repodata/$name.xml"){
			open (IDXFILE, ">$repodata/$name.xml") || die "Could not open $repodata/$name.xml : $!\n";
			print IDXFILE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
            print IDXFILE "<$tag xmlns=\"http://linux.duke.edu/metadata/$name\" packages=\"0\">\n";
            print IDXFILE "<package nil></package></$tag>\n";
            close ( IDXFILE );
		}
		($data{"${name}_header"},$data{"${name}_footer"},$data{"${name}_data"}) = ReadXmlFile("$repodata","$name","$tag");
	}

    my $number_packages = 0;
    my $number_discarded = 0;
    my %seen_rpms = ();
    my %stat_all_rpms = ();
    my @rpm_dirs;

    if (opendir(D, "$repodata/../rpm")) {
        @rpm_dirs = grep {!/^\./} readdir(D);
        closedir D;
    }
    for my $rpm_dir (@rpm_dirs) {
        if (opendir(D, "$repodata/../rpm/$rpm_dir")) {
            for (grep { /^[^\.].*\.rpm/ } readdir(D)) {
                $stat_all_rpms{"$repodata/../rpm/$rpm_dir/$_"} = lstat("$repodata/../rpm/$rpm_dir/$_");
            }
            closedir D;
        }
    }

	LOG("Starting susedata creation",5);
	my $valid_pkgids;

	for my $index (0...$#{$data{'primary_data'}}) {
        my $filename = $data{'primary_data'}->[$index];
        my $pkgid = $data{'primary_data'}->[$index];
        #
        $filename =~ s/^[\s\S]*<location href="([^"]*)"[\s\S]*$/$1/;
        $pkgid =~ s/^[\s\S]*<checksum type="sha" pkgid="YES">([^<]*)<[\s\S]*$/$1/;
        my $filebase = $filename;
        $filebase =~ s/^.*\///;
        #
        my $pack_ok = 0;
        my $f_stat = $stat_all_rpms{"$repodata/../$filename"};
		# get file time
		if ( $f_stat ) {
            my $fil_time = $f_stat->mtime;
            my $rec_time = $data{'primary_data'}->[$index];
            $rec_time =~ s/.*time file=\"([^\"]*).*/$1/s;
            $pack_ok = 1 if ( $rec_time eq $fil_time );
            LOG("$filename $rec_time $fil_time",5) unless $pack_ok;
        }
		if ( $pack_ok && $data{'filelists_data'}->[$index] && $data{'other_data'}->[$index] && $data{'filelists_data'}->[$index] =~ /pkgid="$pkgid"/ && $data{'other_data'}->[$index] =~ /pkgid="$pkgid"/ ) {
            $data{'primary_data'}->[$index] =~ s/\s+$//s;
            $data{'primary_data'}->[$index] = "    <package ".$data{'primary_data'}->[$index];
            $data{'filelists_data'}->[$index] =~ s/\s+$//s;
            $data{'filelists_data'}->[$index] = "<package ".$data{'filelists_data'}->[$index];
            $data{'other_data'}->[$index] =~ s/\s+$//s;
            $data{'other_data'}->[$index] = "<package ".$data{'other_data'}->[$index];

            $seen_rpms{$filename} = 1;
            $number_packages += 1;
            $valid_pkgids->{$pkgid} = 1;
		} else {
			undef $data{'primary_data'}->[$index];
            undef $data{'filelists_data'}->[$index];
            undef $data{'other_data'}->[$index];

            $number_discarded += 1;
			LOG("discarding data for $filename",3);
		}
	}
	for my $index (0...$#{$data{'suse_data'}}) {
        my $pkgid = $data{'suse_data'}->[$index];
        $pkgid =~ s/^.*pkgid=\"([^\"]*)\".*$/$1/s;
        if ($valid_pkgids->{$pkgid}) {
            $data{'suse_data'}->[$index] =~ s/\s+$//s;
            $data{'suse_data'}->[$index] = "    <package ".$data{'suse_data'}->[$index];
        } else {
            undef $data{'suse_data'}->[$index];
            LOG("discarding susedata for **$pkgid**",3);
        }
    }

	LOG("re-using data for $number_packages rpms, discarded data for $number_discarded rpms (".($#{$data{'primary_data'}} + 1).")",3);

	for my $current_rpm (keys %stat_all_rpms) {
        my $short = $current_rpm;
        $short =~ s/$repodata\/..\///;
#        next if ( $seen_rpms{$short} );
#        next if (S_ISLNK($stat_all_rpms{$current_rpm}->mode));
        next if ( $current_rpm =~ /\.patch\.rpm$/ );
        next if ( $current_rpm =~ /\.delta\.rpm$/ );

        my $filebase = $current_rpm;
        $filebase =~ s/^.*\///;

        LOG("adding data for $current_rpm",3);

        my %curpack = GetPackageDataFromRpm($current_rpm);
		if ($config{'license_file'} && -f "$config{'license_file'}"){
			my @lic_text=();
			open (LIC,"< $config{'license_file'}");
			while (<LIC>){
				push @lic_text, xml_escape($_);
			}
			close(LIC);
			$curpack{'confirmlic'}=join("\n",@lic_text);
		}
        my ($a1,$a2,$a3,$a4) = PackageDataToXML(\%curpack);

        my $package_header = "<package pkgid=\"".$curpack{'checksum_sha'}."\" name=\"".$curpack{'name'}."\" arch=\"".$curpack{'rpmarch'}."\"\>\n";
        $package_header .= "<version epoch=\"".$curpack{'epoch'}."\" ver=\"".$curpack{'version_only'}."\" rel=\"".$curpack{'release'}."\"/>\n";
        my $suse_data_entry = $package_header;

		# license to confirm...
        my $conf_lic = "";
		if ($curpack{'confirmlic'}){
            $conf_lic = "      <suse:license-to-confirm>\n".to_xml_utf8($curpack{'confirmlic'})."\n      </suse:license-to-confirm>\n";
            $suse_data_entry .= "<eula>\n".to_xml_utf8($curpack{'confirmlic'})."\n      </eula>\n";
            LOG("adding eula to $current_rpm to susedata",5);
        }
		# support keywords...
		my %keyword_data=();
        if ($config{'keywordfile'}){
			my $keywords=ReadFileToHash("$config{'keywordfile'}") if ($config{'keywordfile'});
			%keyword_data=%$keywords;
			print "$filebase has keyword" if (defined($keyword_data{$filebase}));
        	if ($keyword_data{$curpack{'name'}}) {
            	for (@{$keyword_data{$curpack{'name'}}}) {
                	$suse_data_entry .= "<keyword>".$_."</keyword>\n";
	            }
    	    }
		}
        push @{$data{'suse_data'}}, "$suse_data_entry</package>";
        push @{$data{'primary_data'}}, "$a1$a2      <format>\n$a3      </format>\n$conf_lic    </package>";
        push @{$data{'filelists_data'}}, "$package_header$a4</package>";

        my $other_entry;
        for (@{$curpack{'changelogtime'}}) {
            $other_entry .= "<changelog author=\"".to_xml_utf8(@{$curpack{'changelogname'}}[0])."\" date=\"".$_."\">";
            $other_entry .= to_xml_utf8(@{$curpack{'changelogtext'}}[0])."</changelog>\n";
            shift @{$curpack{'changelogname'}};
            shift @{$curpack{'changelogtext'}};
        }
        push @{$data{'other_data'}}, "$package_header$other_entry</package>";;
        $number_packages += 1;
    }
} else {
	writePatchFile(\%config,$repodata,\@package_data);
	GeneratePatchesXml($repodata);
}

GenerateRepomdXml($repodata);
unlink "$repodata/repomd.xml.asc";
unlink "$repodata/repomd.xml.key";

if ( $config{'do_signing'} ) {
    if ( $config{'sign_id'} ) {
		system("gpg -a -b --default-key \"$config{'sign_id'}\" $repodata/repomd.xml");
    } else {
		system("gpg -a -b $repodata/repomd.xml");
		$config{'sign_id'} = `gpg --verify $repodata/repomd.xml.asc 2>&1 | sed -ne "s/.* ID //p"`;
		chomp ($config{'sign_id'});
    }
    system("gpg -a --export \"$config{'sign_id'}\" > $repodata/repomd.xml.key") if ( $config{'sign_id'} );
}

LOG("Finished creation for $repodata",1);
close (OUTPUT_LOG);
cleanup();

#system("//bin/sign -d $patches_directory/repomd.xml");
#system("cp $patchinfo_lib_dir/public-key $patches_directory/repomd.xml.key");

# Logfile:
# $Log: createpatch.pl,v $
# Revision 1.6  2009/04/27 09:02:13  lrupp
# - enable keywords support
# - added PackageDataToXML()
# - use/fillup suse_data primary_data filelists_data
#
# Revision 1.5  2009/04/17 15:13:47  lrupp
# - weekend :-)
#
# Revision 1.4  2009/04/17 08:15:28  lrupp
# - new writePatchFile()
# - remove validate option: we always produce valid metadata ;-)
# - add logfile and lockfile
#
# Revision 1.3  2009/04/16 16:00:27  lrupp
# - use %config for all configuration now
# - be backwarts compatible: allow basedir as argument without option
# - added configfile option
#
# Revision 1.2  2009/04/16 14:09:02  lrupp
# - use temdir for update_repo
# - new parsePrimaryXml()
# - use Getopt for config options
#
# Revision 1.1  2009/04/16 13:34:01  lrupp
# Initial revision
#
# Revision 1.5  2007/12/11 13:42:01  lrupp
# - added "license-to-confirm"
# - check for createrepo and warn user if not exist
#
# Revision 1.4  2007/07/13 08:44:35  lrupp
# addad @packagelist to condition
#
# Revision 1.3  2007/05/15 15:59:21  lrupp
# beautify usage message
#
#
0707010000000E000081ED0000000000000000000000015C0E85F6000012CD000000000000000000000000000000000000003B00000000inst-source-utils-2018.12.10/usr/bin/gen-s390-cd-kernel.pl#!/usr/bin/perl -w
#
# Generates a bootable CD-ROM for S/390
#
# Copyright (C) 2006 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# $Id: gen-s390-cd-kernel.pl 107 2009-03-06 11:48:14Z ro $

use FileHandle;
use Getopt::Long;
use strict;

# Help text
#
sub help($) {
	my $exitcode = shift || 1;
    print "Usage: $0 <OPTIONS> - generate a kernel image for CD-ROM boot\n";
    print "SYNOPSIS: $0 [--initrd=file] \n";
	print "             [--parmfile=file] [--outfile=file] \n";
	print "	            [--kernel=file] [--cmdline=string] \n";
    exit $exitcode;
}

# Parse command line options
my ($initrd,       $image,        $parmfile, $outfile,        $cmdline ) =
   ('/boot/initrd','/boot/image', '',        '/tmp/image.cd', 'root=/dev/sda2');

Getopt::Long::Configure ("bundling");
eval {
    unless (GetOptions (
	'i|initrd=s' => \$initrd,
	'k|kernel=s' => \$image,
	'p|parmfile=s' => \$parmfile,
	'o|outfile=s' => \$outfile,
	'c|cmdline=s' => \$cmdline,
	'h|help' => sub { help(0); } )) {
	help(1);
    }
};

if ($@) {
    print "$@";
    help(1);
}

# Open input files
sysopen(image_fh,$image,O_RDONLY) or die "Cannot open $image: $!\n";
sysopen(initrd_fh,$initrd,O_RDONLY) or die "Cannot $initrd: $!\n";

my $image_size = (stat(image_fh))[7];
my $initrd_size = (stat(initrd_fh))[7];

# Get the size of the input files
printf("%s: offset 0x%x len 0x%x (%d blocks)\n", 
       $image, 0, $image_size, ($image_size >> 12) + 1);

# The kernel appearently needs some free space above the
# actual image (bss? stack?), so use this hard-coded
# limit (from include/asm-s390/setup.h)

# my $initrd_offset = (($image_size >> 12) + 1) << 12;
my $initrd_offset = 0x800000;
my $boot_size = ((($initrd_offset + $initrd_size) >> 12) + 1 ) << 12;
printf("%s: offset 0x%x len 0x%x (%d blocks)\n", 
       $initrd, $initrd_offset, $initrd_size, ($initrd_size >>12) + 1);
printf("%s: len 0x%x (%d blocks)\n", 
       $outfile, $initrd_offset + $initrd_size, $boot_size / 4096);

# Get the kernel command line arguments
$cmdline .= " " if ($cmdline ne "");

if ($parmfile ne "") {
    my $line;

    $cmdline = '';
    open(parm_fh,$parmfile) or die "Cannot open $parmfile: $!\n";
    while($line=<parm_fh>) {
	    chomp $line;
        $cmdline .= $line . " ";
    }
    close(parm_fh);
}

if ($cmdline ne "") {
    chop $cmdline;
}

# Max length for the kernel command line is 896 bytes
die "Kernel commandline too long (". length($cmdline) ." bytes)\n" if (length($cmdline) >= 896);

# Now create the image file.
sysopen(out_fh,$outfile,O_RDWR|O_CREAT|O_TRUNC) or die "Cannot open $outfile: $!\n";

# First fill the entire size with zeroes
sysopen(null_fh,"/dev/zero",O_RDONLY) or die "Cannot open /dev/zero: $!\n";

my $buffer="";
my $blocks_read=0;
while ($blocks_read < ($boot_size >> 12)) {
    sysread(null_fh,$buffer, 4096);
    syswrite(out_fh,$buffer);
    $blocks_read += 1;
}

print "Read $blocks_read blocks from /dev/zero\n";
close(null_fh);

# Now copy the image file to location 0
sysseek(out_fh,0,0);
$blocks_read = 0;
while (sysread(image_fh,$buffer, 4096) != 0) {
    syswrite(out_fh,$buffer,4096);
    $blocks_read += 1;
}

print "Read $blocks_read blocks from $image\n";
close(image_fh);

# Then the initrd to location specified by initrd_offset
sysseek(out_fh,$initrd_offset,0);
$blocks_read = 0;
while (sysread(initrd_fh,$buffer, 4096) != 0) {
    syswrite(out_fh,$buffer,4096);
    $blocks_read += 1;
}

print "Read $blocks_read blocks from $initrd\n";

close(initrd_fh);

# Now for the real black magic.
# If we are loading from CD-ROM or HMC, the kernel is already loaded
# in memory by the first loader itself.
print "Setting boot loader control to 0x10000\n";

sysseek(out_fh,4,0 );
syswrite(out_fh,pack("N",0x80010000),4);

print "Writing kernel commandline (". length($cmdline) ." bytes):\n$cmdline\n";

sysseek(out_fh,0x10480,0);
syswrite(out_fh,$cmdline,length($cmdline));

print "Setting initrd parameter: offset $initrd_offset size $initrd_size\n";

sysseek(out_fh,0x1040C,0);
syswrite(out_fh,pack("N",$initrd_offset),4);
sysseek(out_fh,0x10414,0);
syswrite(out_fh,pack("N",$initrd_size),4);

close(out_fh);
0707010000000F000081ED0000000000000000000000015C0E85F6000016C0000000000000000000000000000000000000003200000000inst-source-utils-2018.12.10/usr/bin/mk_changelog#!/usr/bin/perl

# Copyright (C) 2006 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#


BEGIN {
  unshift @INC, "/usr/share/inst-source-utils/modules";
}

$| = 1;

use strict;
use Cwd;
use Time::localtime;
use Time::Local;
use RPMQ;

# current date minus two years
my $min_date = time - 2*365*24*3600;
my %month_to_num = (Jan=>0,Feb=>1,Mar=>2,Apr=>3,May=>4,Jun=>5,Jul=>6,Aug=>7,Sep=>8,Oct=>9,Nov=>10,Dec=>11);
my $delimiter = "------------------------------------------------------------------";
my $actual = 0;
my $skip_rest = 0;
my %entries = ();
my %packages = ();
my $announce_string = "";

# environment
my $current_client = $ARGV[0];
chomp ( $current_client = getcwd ) unless ( $current_client );
my $root_on_cd = $ENV{"ROOT_ON_CD"};
$root_on_cd = "suse" unless ($root_on_cd);

my $cds_prim = "";
my @pactreeCDall = ();

if ( -d "$current_client/DVD1/$root_on_cd" ) {
    $cds_prim = "$current_client/DVD1";
    for my $i (1...9) {
	push @pactreeCDall, "$current_client/DVD$i/$root_on_cd" if ( -d "$current_client/DVD$i/$root_on_cd" );
    }
} elsif ( -d "$current_client/CD1/$root_on_cd" ) {
    $cds_prim = "$current_client/CD1";
    for my $i (1...9) {
	push @pactreeCDall, "$current_client/CD$i/$root_on_cd" if ( -d "$current_client/CD$i/$root_on_cd" );
    }
} else {
    $cds_prim = "$current_client";
    push @pactreeCDall, "$current_client/$root_on_cd";
}
  
my $distro = $ENV{"BBASENAME"};
$distro = "all" unless ($distro);
#print "cds_prim is $cds_prim\n";
#print "distro   is $distro\n";

sub process_line {
   my ($myline,$package) = @_;
   chomp ($myline);
   next if ($myline =~ /^--$/);
   next if ($myline =~ /^=========================================*$/);
   if ($myline =~ /^\* .* - .*\@.*/) {
    my @datarray = split ( ' ',$myline);
    my $last_actual = $actual;
    if ( $datarray[4] < 1980 || $datarray[3] < 1  || $datarray[2] < 0
      || $datarray[4] > 2100 || $datarray[3] > 31 || $datarray[2] > 11 ) {
         $datarray[2] = 1;
         $datarray[3] = 1;
         $datarray[4] = 1;
         warn ("invalid date line in $package: $myline\n");
    }
    my $monthnum = $month_to_num{$datarray[2]};
    $actual = timelocal ( 0,0,0,$datarray[3],$monthnum, $datarray[4]-1900);
    if ( $actual < $min_date ) {
        $skip_rest = 1;
        next;
    }
    if ( $last_actual ne $actual ) {
       $entries{$actual} .= "\n$announce_string\n";
    }
    next;
  }
  if ($myline =~ /^\s*-/) {
    $myline =~ s/^\s*(\S*)/$1/;
    $myline =~ s/(\S*)\s*$/$1/;
    $entries{$actual} .= "  $myline\n";
    next;
  }
  if ($myline =~ /\S/) {
    $myline =~ s/^\s*(\S*)/$1/;
    $myline =~ s/(\S*)\s*$/$1/;
    $entries{$actual} .= "    $myline\n";
  }
}


my $findstr .= join(" ",@pactreeCDall);
my $lasttime = "";
#print "findstr = $findstr\n";
my %allrpms = ();
open ( RPMLIST , "find $findstr -maxdepth 2 -name \"*.rpm\" -print |");
while ( my $myrpm = <RPMLIST> ) {
    chomp ($myrpm);
    my $basename = $myrpm;
    $basename =~ s/^.*\///;
    $allrpms{$basename} = $myrpm;
}
close ( RPMLIST );

my $all_num = keys (%allrpms);
my $cur_num = 0;

for my $myrpm (sort (keys (%allrpms))) {
    my $myfile = $allrpms{$myrpm};
    $cur_num++;
    print "$all_num - $cur_num\r" if ( -t STDOUT );
    chomp ( $myfile );
    next unless ( -f $myfile );
    next unless ( $myfile =~ /\.rpm$/ );
    my $basename = $myfile;
    $basename =~ s/^.*\///;
    # NAME and SOURCERPM
    my %p_res = RPMQ::rpmq_many($myfile,1000,1044);
    my $package_r = ($p_res{1000} || [])->[0];
    my $srcrpm = ($p_res{1044} || [])->[0];
    next unless ($srcrpm);
    my $package = $srcrpm;
    $package =~ s/-[^-]*-[^-]*$//;
    next if ( $packages{$srcrpm} );
    $packages{$srcrpm} = 1;
    $announce_string = "++++ $package:\n";
    # CHANGELOGTIME, CHANGELOGTEXT
    my %c_res = RPMQ::rpmq_many($myfile,1080,1082);
    for my $mytime (@{$c_res{1080} || []}) {
	  last if ( $mytime < $min_date );
	  $entries{$mytime} .= "\n$announce_string\n" if ( $lasttime ne $mytime );
	  $lasttime = $mytime;
	  for my $myline (split("\n",@{$c_res{1082} || []}[0])) {
	    $myline =~ s/^\s*(\S*)/$1/;
	    $myline =~ s/(\S*)\s*$/$1/;
	    if ( $myline =~ /^-/ ) {
		    $entries{$mytime} .= "  $myline\n";
	    } else {
		    $entries{$mytime} .= "    $myline\n";
	    }
	  }
	  shift @{$c_res{1082} || []};
    }
}
#print "\n";
unlink "$cds_prim/ChangeLog";
open ( CHANGELOG , "> $cds_prim/ChangeLog" );
my $clog = "Changelog.$distro -----------------";
my $clog_len = length ( $clog );
my $clog_rest = 25 - $clog_len;
my $mydate = `date`;
chomp ($mydate);
print CHANGELOG "$delimiter\n";
printf CHANGELOG "--- %.25s %s ------\n" , $clog , $mydate;
print CHANGELOG "$delimiter\n";


foreach my $key (sort {0+$b <=> 0+$a} (keys %entries)) {
  my $ltime = localtime $key;
  my $kyear = $ltime->year + 1900;
  my $kmon  = $ltime->mon + 1;
  my $kmon_ascii = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$ltime->mon];
  my $kday  = $ltime->mday;
  print CHANGELOG "$delimiter\n------------------  $kyear-$kmon-$kday  -  $kmon_ascii $kday $kyear  -------------------\n$delimiter\n";
  print CHANGELOG "$entries{$key}\n";
}

close ( CHANGELOG );
07070100000010000081ED0000000000000000000000015C0E85F60000234D000000000000000000000000000000000000003100000000inst-source-utils-2018.12.10/usr/bin/mk_listings#!/usr/bin/perl
#
# Copyright (C) 2007 Novell Inc.   
#
# This program is free software; you can redistribute it and/or   
# modify it under the terms of the GNU General Public License 2
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,   
# but WITHOUT ANY WARRANTY; without even the implied warranty of   
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   
# GNU General Public License for more details.   
#
# You should have received a copy of the GNU General Public License   
# along with this program; if not, write to the 
# Free Software Foundation, Inc., 
# 51 Franklin Street, 
# Fifth Floor, 
# Boston, MA  02110-1301, 
# USA.
#
# $Id$

sub cp {
  my $from = shift;
  my $to = shift;
  $to =~ s/\/+$//;
  if (-d $to) {
    return undef unless $from =~ /([^\/]+)$/;
    $to = $to ne '' ? "$to/$1" : "$1";
  }
  return 1 if "$to" eq "$from";
  if (!open(FROM, "<$from")) {
    error("cp: $from: $!\n");
    return undef;
  }
  unlink("$to");
  if (!open(TO, ">$to")) {
    my $errno = $!;
    close FROM;
    $! = $errno;
    error("cp: $to: $!\n");
    return undef;
  }
  my $l;
  while ($l = <FROM>) {
    print TO $l;
  }
  close FROM;
  if (!close(TO)) {
    error("cp: $to: $!\n");
    return undef;
  }
  return 1;
}

sub usage {
print <<EOF

Usage: $0 [directory]

       Creates the files ls-lR.gz, INDEX.gz and ARCHIVES.gz in the directory.
       Containing all content of all files in the directory and his sub-
       directories. 
       Useful for searching for special files on the media using tools like 
       pin or just zgrep.

EOF
;

exit $_[0] || 0;

}

if (( $ARGV[1] eq "-h" ) || ( $ARGV[1] eq "--help" )){
  usage(0);
}

$ENV{'LC_CTYPE'}="en_US.UTF-8";

my $rsyncable = "";

my $arg = shift @ARGV;
my $tmpdir = `mktemp -d /tmp/mk_listings.XXXXXX`;
chomp ($tmpdir);
if ( "$arg" ) {
    usage(1) unless ( -d "$arg" );
}

if ( "$arg" !~ /^\// ) {
    $pwd = `pwd`;
    chomp ($pwd);
    $arg = "$pwd/$arg";
}

$arg=~ s/ /\\ /g;
my $cd_replace = "/CD";
my $arg_base = "$arg";
$arg_base =~ s/^.*\/([^\/]*)$/$1/;
$cd_replace = "/DVD" if ( "$arg_base" =~ /-dvd(.*)/ );
$cd_replace = "/inst-source" if ( "$arg_base" =~ /^stable-oss/ );

system (`touch "$tmpdir/fff"`);
system (`gzip --rsyncable "$tmpdir/fff" >/dev/null 2>/dev/null`);
if ( -f "$tmpdir/fff.gz" ) {
    $rsyncable = "--rsyncable";
}
system (`rm -f "$tmpdir/fff" "$tmpdir/fff.gz"`);

print "INFO:    creating ls-lR.gz, INDEX.gz and ARCHIVES.gz\n";

open ( FINDALL , "cd \"$arg\" ; find . -type f | grep -vE \"allrpms|\.cr-cache|\.snapshot\" |");
my @FINDALL = <FINDALL>;
close ( FINDALL );
my @FINDALL2 = @FINDALL;

my @FIND_RPMS = ();
my @FIND_TARZ = ();
my @FIND_TARBZ = ();
my @FIND_TAR = ();
my @FIND_DEB = ();
for (@FINDALL) {
    push @FIND_RPMS, $_ if ( /\.rpm$/ || /\.spm$/ );
    push @FIND_TARZ, $_ if ( /\.tar.gz$/ || /\.tar.Z$/ || /\.tgz$/ || /\.tar.z$/ || /\.taz$/ );
    push @FIND_TARBZ, $_ if ( /\.tar.bz2$/ || /\.tbz$/ );
    push @FIND_TAR, $_ if ( /\.tar$/ );
    push @FIND_DEB, $_ if ( /\.deb$/ );
}

open ( ARCHIVES, "| gzip $rsyncable > $tmpdir/ARCHIVES.gz");

print ARCHIVES <<EOF;
---------------------------------------------------------------------
---------------------------------------------------------------------
--------------- Here comes contents of all files: -------------------
------ *.rpm *.tar.gz *.tar.Z *.tgz *.taz *.tar.z *.tar *.deb -------
------------------ found in any subdirectory ------------------------
---------------------------------------------------------------------
---------------------------------------------------------------------
EOF

my $curnum = 0;
my $all_num = $#FIND_RPMS + $#FIND_TARZ + $#FIND_TARBZ + $#FIND_TAR + $#FIND_DEB + 5;

for (@FIND_RPMS) {
   $curnum++;
   print "$curnum/$all_num\r" if ( -t STDOUT );
   my $filename = "$_";
   chomp($filename);
   my $print_name = "$filename";
   $print_name =~ s/\/CD/$cd_replace/;
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "---> $print_name\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   my $nodigest = "";
   if ( !system("rpm --nodigest 2>/dev/null") ) {
	$nodigest = "--nodigest --nosignature";
   }
   $filename=~ s/ /\\ /g;
   open (RPML,"rpm $nodigest -qpilv \"$arg/$filename\"|");
   while (<RPML>) {
      print ARCHIVES "$print_name:    $_";
   }
   close (RPML);
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
}

for (@FIND_TARZ) {
   $curnum++;
   print "$curnum/$all_num\r" if ( -t STDOUT );
   my $filename = "$_";
   chomp($filename);
   my $print_name = "$filename";
   $print_name =~ s/\/CD/$cd_replace/;
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "---> $print_name\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   open (TARL,"tar ztvf \"$arg/$filename\"|");
   while (<TARL>) {
      print ARCHIVES "$print_name:    $_";
   }
   close (TARL);
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
}

for (@FIND_TARBZ) {
   $curnum++;
   print "$curnum/$all_num\r" if ( -t STDOUT );
   my $filename = "$_";
   chomp($filename);
   my $print_name = "$filename";
   $print_name =~ s/\/CD/$cd_replace/;
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "---> $print_name\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   open (TARL,"tar jtvf \"$arg/$filename\"|");
   while (<TARL>) {
      print ARCHIVES "$print_name:    $_";
   }
   close (TARL);
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
}

for (@FIND_TAR) {
   $curnum++;
   print "$curnum/$all_num\r" if ( -t STDOUT );
   my $filename = "$_";
   chomp($filename);
   my $print_name = "$filename";
   $print_name =~ s/\/CD/$cd_replace/;
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "---> $print_name\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   open (TARL,"tar tvf \"$arg/$filename\"|");
   while (<TARL>) {
      print ARCHIVES "$print_name:    $_";
   }
   close (TARL);
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
}

for (@FIND_DEB) {
   $curnum++;
   print "$curnum/$all_num\r" if ( -t STDOUT );
   my $filename = "$_";
   chomp($filename);
   my $print_name = "$filename";
   $print_name =~ s/\/CD/$cd_replace/;
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "---> $print_name\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   open (DEBL,"ar pf \"$arg/$filename\" data.tar.gz | tar tzvf -|");
   while (<DEBL>) {
      print ARCHIVES "$print_name:    $_";
   }
   close (DEBL);
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
   print ARCHIVES "-----------------------------------------------------------------\n";
}

close (ARCHIVES);
cp ("$tmpdir/ARCHIVES.gz","$arg/ARCHIVES.gz");

open ( LSLR , "cd \"$arg\" ; ls -lR |" );
open ( LSLRZ, "| gzip $rsyncable > $tmpdir/ls-lR.gz");
while (<LSLR>) {
   next if ( /\.listing$/ );
   $_ =~ s/\/CD/$cd_replace/;
   print LSLRZ "$_";
}
close (LSLR);
close (LSLRZ);
cp ("$tmpdir/ls-lR.gz","$arg/ls-lR.gz");

open ( INDEX, "| gzip $rsyncable > $tmpdir/INDEX.gz");
for (@FINDALL2) {
   next if ( /\.listing$/ );
   $_ =~ s/\/CD/$cd_replace/;
   print INDEX "$_";
}
close (INDEX);
cp ("$tmpdir/INDEX.gz","$arg/INDEX.gz");

system("rm -rf $tmpdir");

if ( -d "$arg/CD1" ) {
    unlink "$arg/CD1/ARCHIVES.gz" if ( -f "$arg/CD1/ARCHIVES.gz" );
    link "$arg/ARCHIVES.gz","$arg/CD1/ARCHIVES.gz";
}

for (1...9) {
    next unless ( -d "$arg/CD$_" );
    unlink "$arg/CD$_/INDEX.gz" if ( -f "$arg/CD$_/INDEX.gz" );
    link "$arg/INDEX.gz", "$arg/CD$_/INDEX.gz";
    unlink "$arg/CD$_/ls-lR.gz" if ( -f "$arg/CD$_/ls-lR.gz" );
    link "$arg/ls-lR.gz","$arg/CD$_/ls-lR.gz";
}
07070100000011000081ED0000000000000000000000015C0E85F600001AA0000000000000000000000000000000000000003600000000inst-source-utils-2018.12.10/usr/bin/packages2eula.pl#! /usr/bin/perl -w
#
# packages2eula.pl -- generates a concatenated EULA.txt from a packages file
#
# (C) 2007, jw@suse.de, Novell Inc.
# Distributable under GPLv2 or GPLv3.
#
# This implements https://keeper.suse.de/webfate/match/id?value=302018
#
# $Id: packages2eula.pl,v 1.4 2007/08/06 17:35:36 jw Exp jw $
# $Log: packages2eula.pl,v $
# Revision 1.4  2007/08/06 17:35:36  jw
# do not modify EULA.txt if no licenses found. (did append = = END = =) before.
#
# Revision 1.3  2007/08/06 17:34:57  jw
# *** empty log message ***
#
# Revision 1.2  2007/08/06 17:34:02  jw
# *** empty log message ***
#
# Revision 1.1  2007/06/05 12:24:39  root
# Initial revision
#

use Data::Dumper;

my $version = '1.1';
my $verbose = 1;
my $in_file;
my $out_file;
my $packages_file_def = 'suse/setup/descr/packages.en';
my $packages_file;
my $with_content = 1;
my $with_listing = 1;
my $translation_archive = "/media.1/licenses.zip";

while (defined (my $arg = shift))
  {
    if    ($arg !~ m{^-.})              { unshift @ARGV, $arg; last }
    elsif ($arg =~ m{^(-h|--help|-\?)}) { exit usage(); }
    elsif ($arg =~ m{^--?v})            { $verbose++; }
    elsif ($arg =~ m{^--?q})            { $verbose = 0; }
    elsif ($arg =~ m{^--?i})            { $in_file = shift; }
    elsif ($arg =~ m{^--?o})            { $out_file = shift; }
    elsif ($arg =~ m{^--?p})            { $packages_file = shift; }
    elsif ($arg =~ m{^--?c})		{ $with_content = !$with_content; }
    elsif ($arg =~ m{^--?l})		{ $with_listing = !$with_listing; }
    else { exit usage("unknown option $arg"); }
  }

$out_file ||= '-';
$in_file = $out_file if !$in_file and $out_file ne '-';
$out_file = $in_file if $out_file eq '=';
unless (defined $packages_file)
  {
    $packages_file = $packages_file_def; 	#  default from current dir.
    
    unless (-f $packages_file)			# try relative to $in_file
      {
        ($packages_file = ($in_file||'')) =~ s{[^/]+$}{};
        $packages_file .= $packages_file_def;
      }
    
    unless (-f $packages_file)			# try relative to $out_file
      {
        ($packages_file = ($out_file||'')) =~ s{[^/]+$}{};
        $packages_file .= $packages_file_def;
      }
  }

exit usage("need at least one of -i or -o\n") unless $in_file and $out_file;

print "using packages_file: $packages_file\n" if $verbose;
open P, "<", $packages_file or die "cannot read $packages_file: $!\n";

my $pkg;
my %eul;
my $name = '';
while (defined(my $line = <P>))
  {
    chomp $line;
    next if $line =~ m{^#};
    if ($line =~ m{^([+=])(\w+):\s*(.*)$})
      {
        my ($sign, $key, $val) = ($1,$2,$3);
	if ($sign eq '+')
	  {
	    while (defined($line = <P>))
	      {
	        last if $line =~ m{^\-$key:\s*$};
	        $val .= $line;
	      }
	  }
	if ($key eq 'Pkg')
	  {
	    $val =~ s{\s+$}{};
	    my @n = split /\s+/, $val;
	    $name = "$n[0]-$n[1]-$n[2]";
	    $pkg->{$name}{name} = $n[0];
	    $pkg->{$name}{version} = $n[1];
	    $pkg->{$name}{release} = $n[2];
	    $pkg->{$name}{arch} = $n[3];
	  }
	elsif ($key =~ m{(Eul|Sum)})
	  {
	    next unless $name;	# packages.en starts with "=Ver: 2.0"

	    $pkg->{$name}{$key} = decode_richtext($val);
	    push @{$eul{$pkg->{$name}{$key}}{pkg}}, $name if $key eq 'Eul';
	  }
        # ignore all other keys.
      }
  }
close P;

# find license titles
for my $e (keys %eul)
  {
    my $head = '';
    while ($e =~ m{^(.*)$}mg)
      {
        my $h = $1;
	$h =~ s{^\s+}{};
	$h =~ s{\s+$}{};
	next unless length $h;

	$head .= "\n$h";
	last if good_title($head);
      }
    $eul{$e}{head} = $head;
    $eul{$e}{body} = $e;
  }

# sort by title
my @eul = sort { lc $a->{head} cmp lc $b->{head} } values %eul;
undef %eul;

for my $i (0..$#eul)
  {
    $eul[$i]{app} = sprintf "APPENDIX_%d", $i+1;
    $eul[$i]{lst} = $with_listing ? "(" . join(' ', sort @{$eul[$i]{pkg}}) . ")\n\t" : "";
  }

# preload the $in_file, in case in_file and out_file are identical.
open IN, "<", $in_file or die "$0: failed to read $in_file: $!\n";
my $novell_eula = join '', <IN>;
close IN;
if ($novell_eula =~ m{= = = = = = = = = \s+Content:\n.*\s+APPENDIX_\d\n}s and
    $novell_eula =~ m{= = = = = = = = = END( =)+\s*$}s)
  {
    warn "\nWARNING: Looks like Appendices are already present in $in_file.\n\n";
    exit 0;
  }

open OUT, ">$out_file" or die "$0: failed to open $out_file: $!\n";

# 1) copy input EULA text verbatim.
print OUT $novell_eula;

# 2) append a content listing, if desired
if ($with_content and scalar @eul)
  {
    print OUT "\n".("= " x 33)."\n";
    print OUT "\nContent:\n";
    for my $e (@eul)
      {
        print OUT "$e->{head}\n\t$e->{lst} See $e->{app}\n";
      }
    print OUT "\n";
  }

# 3) append each EULA with a separtion line containing AppendixN
# so that we can jump directly.
for my $e (@eul)
  {
    print OUT "\n".("= " x 14).$e->{app}.(" =" x 13)."\n$e->{lst}\n";
    print OUT $e->{body};
  }

print OUT "\n".("= " x 16)."END".(" =" x 15)."\n" if scalar @eul;
close OUT or die "could not write $out_file: $!\n";

printf STDERR "%d Appendices written.\n", scalar @eul if $verbose;

exit 0;
############################################################

# get EULA header: first line, plus second text line
# if the word 'license' oder 'agreement' are not in first.
# but only 'End User License Agreement' is insufficient.
sub good_title
{
  my ($text) = @_;
  return 0 unless $text =~ m{(license|licence|agreement)}i;
  $text =~ s{(license|licence|agreement|end|user)}{}gi;
  return 0 if $text =~ m{^\s*$}s;
  return 1;
}

sub decode_richtext
{
  my ($txt) = @_;
  return $txt unless $txt =~ s{^\Q<!-- DT:Rich -->\E}{};
  $txt =~ s{<p>\s*}{\n}g;
  $txt =~ s{</p>\s*}{\n}g;
  $txt =~ s{&quot;}{"}g;
  $txt =~ s{&#39;}{'}g;
  $txt =~ s{<ol>\s*}{\n}g;
  $txt =~ s{<li>\s*}{ * }g;
  $txt =~ s{</li>\s*}{}g;
  $txt =~ s{</ol>\s*}{\n}g;

  $txt =~ s{</\w+>\s*}{}g;
  $txt =~ s{^\s+}{}g;
  $txt =~ s{\s+$}{}g;
  return $txt;
}

sub usage
{
  my ($msg) = @_;
  print STDERR qq{$0 V$version usage:

encoding [options] [file]

valid options are:
 -h                         Print this online help
 -v                         Be more verbose. Default $verbose
 -q                         Be quiet
 -i inputEULA.txt           Defaults to the same name as given with -o
 -o outputEULA.txt          Defaults to stdout, if also -i is given.
 			    Use -o = for inplace modification.
 -p packages_file           Defaults to '$packages_file_def'; tested also relative 
                            to -i and -o argument.
 -c                         Toggle writing of a content table. 
                            Default: $with_content.
 -l                         Toggle writing of package listing corresponding
                            to the added EULAs.  Default: $with_listing.
};
  print STDERR "\nERROR: $msg\n" if $msg;
  return 0;
}

07070100000012000081ED0000000000000000000000015C0E85F600000C51000000000000000000000000000000000000003A00000000inst-source-utils-2018.12.10/usr/bin/rezip_repo_rsyncable#!/usr/bin/perl

BEGIN {
  $abuild_base_dir = "/usr/share/inst-source-utils";
  unshift @INC, "$abuild_base_dir/modules";
}


use strict;
use File::stat;
use ABStructured ':bytes';
use ABXML;
use Digest;



sub GenerateRepomdXml {
    my ($repodir) = @_;
    my $repobase = $repodir;
    $repobase =~ s/\/repodata//;
    open (REPOMD, "<", "$repodir/repomd.xml");
    my $repomd_raw = join("",<REPOMD>);
    close (REPOMD);
    my $repomd = XMLin($ABXML::repomd, $repomd_raw);
    for my $record (@{$repomd->{'data'}}) {
      my $filename = $record->{'location'}->{'href'};
      my $checksumstring = $record->{'checksum'}->{'type'};
      my $checksumtype = uc($checksumstring);
      $checksumtype =~ s/([0-9]+)/-$1/;
      $checksumtype .= "-1" unless $checksumtype =~ /[0-9]/;
      next unless open(REC, "<", "$repobase/$filename");
      my $ctx = Digest->new($checksumtype);
      $ctx->addfile(*REC);
      my $newfilechksum = $ctx->hexdigest();
      close (REC);
      if ($filename =~ /^([^\/]*\/)?[0-9a-f][0-9a-f]*-(.*\.gz)$/) {
	my $new_filename = "$1$newfilechksum-$2";
	rename ("$repobase/$filename","$repobase/$new_filename");
	$filename = $new_filename;
	$record->{'location'}->{'href'} = $filename;
      }
      my $nstat = stat("$repobase/$filename");
      my $newfiletime = $nstat->mtime;
      my $newfilesize = $nstat->size;
      $record->{'checksum'} = { 'type' => $checksumstring, '_content' => $newfilechksum };
      $record->{'timestamp'} = $newfiletime;
      $record->{'size'} = $newfilesize if $record->{'size'};
    }

    open (REPOMD, ">", "$repodir/repomd.xml");
    print REPOMD "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    print REPOMD XMLout($ABXML::repomd, $repomd);
    close (REPOMD);
}

my $rsyncable = "";

my $arg = shift @ARGV;
my $tmpdir = `mktemp -d /tmp/rezip_repo_rsyncable.XXXXXX`;
chomp ($tmpdir);
if ( $arg ) {
    die("need an argument") unless ( -d $arg );
}

if ( $arg !~ /^\// ) {
    my $pwd = `pwd`;
    chomp ($pwd);
    $arg = "$pwd/$arg";
}

$arg .= "/repodata" unless $arg =~ /\/repodata/;

system ("touch", "$tmpdir/fff");
system ("gzip --rsyncable \"$tmpdir/fff\" >/dev/null 2>/dev/null");
if ( -f "$tmpdir/fff.gz" ) {
    $rsyncable = "--rsyncable";
}
unlink ("$tmpdir/fff");
unlink ("$tmpdir/fff.gz");

if ( $rsyncable ) {
  my @GZIPPED = glob("$arg/*.gz");
  for (@GZIPPED) {
    system ("touch", "--reference", "$_", "$_.timestamp");
    system ("gunzip", "-f", $_);
    $_ =~ s/.gz$//;
    system ("gzip", "-9", "-n", $rsyncable, $_);
    system ("touch", "--reference", "$_.gz.timestamp", "$_.gz");
    unlink ("$_.gz.timestamp");
  }
  my $has_sign = "";
  $has_sign = "1" if ( -f "$arg/repomd.xml.asc" );
  system ("cp", "-a", "$arg/repomd.xml.key", $tmpdir) if ( -f "$arg/repomd.xml.key" );
  if ( -f "$arg/repomd.xml" ) {
    GenerateRepomdXml($arg);
  }
  if ( $has_sign ) {
    unlink "$arg/repomd.xml.asc";
    system ("sign", "-d", "$arg/repomd.xml");
  }
  if ( -f "$tmpdir/repomd.xml.key" ) {
    system ("cp", "-a", "$tmpdir/repomd.xml.key", $arg);
  }
  if ( -f "$arg/MD5SUMS" ) {
    system ("create_md5sums", $arg);
  }
}

system("rm", "-r", "-f", $tmpdir);

07070100000013000041ED0000000000000000000000035C0E85F600000000000000000000000000000000000000000000002700000000inst-source-utils-2018.12.10/usr/share07070100000014000041ED0000000000000000000000035C0E85F600000000000000000000000000000000000000000000003900000000inst-source-utils-2018.12.10/usr/share/inst-source-utils07070100000015000041ED0000000000000000000000025C0E85F600000000000000000000000000000000000000000000004100000000inst-source-utils-2018.12.10/usr/share/inst-source-utils/modules07070100000016000081A40000000000000000000000015C0E85F6000034CC000000000000000000000000000000000000005100000000inst-source-utils-2018.12.10/usr/share/inst-source-utils/modules/ABStructured.pm
package ABStructured;

use vars qw($VERSION @ISA @EXPORT);

require Exporter;
@ISA               = qw(Exporter);
@EXPORT            = qw(XMLin XMLinfile XMLout);
$VERSION           = '1.0';

use XML::Parser;
use Encode;

use strict;

our $bytes;

sub import {
  $bytes = 1 if grep {$_ eq ':bytes'} @_;
  __PACKAGE__->export_to_level(1, grep {$_ ne ':bytes'} @_);
}

sub _workin {
  my ($how, $out, $ain, @in) = @_;
  my @how = @$how;
  my $am = shift @how;

  my %known = map {ref($_) ? (!@$_ ? () : (ref($_->[0]) ? $_->[0]->[0] : $_->[0] => $_)) : ($_=> $_)} @how;
  for my $a (keys %$ain) {
    die("unknown attribute: $a\n") unless $known{$a};
    if (ref($known{$a})) {
      die("attribute '$a' must be element\n") if @{$known{$a}} > 1 || ref($known{$a}->[0]);
      push @{$out->{$a}}, $ain->{$a};
    } else {
      die("attribute '$a' must be singleton\n") if exists $out->{$a};
      $out->{$a} = $ain->{$a};
      Encode::_utf8_off($out->{$a}) if $bytes;
    }
  }
  while (@in) {
    my ($e, $v) = splice(@in, 0, 2);
    my $ke = $known{$e};
    if ($e eq '0') {
      next if $v =~ /^\s*$/s;
      die("element '$am' contains content\n") unless $known{'_content'};
      Encode::_utf8_off($v) if $bytes;
      $v =~ s/\s+$/ /s;
      $v =~ s/^\s+/ /s;
      if (exists $out->{'_content'}) {
        $out->{'_content'} =~ s/ $//s if $v =~ /^ /s;
        $out->{'_content'} .= $v;
      } else {
        $out->{'_content'} = $v;
      }
      next;
    }
    if (!$ke && $known{''}) {
      $ke = $known{''};
      $v = [{}, $e, $v];
      $e = '';
    }
    die("unknown element: $e\n") unless $ke;
    if (!ref($ke)) {
      push @$v, '0', '' if @$v == 1;
      die("element '$e' contains attributes @{[keys %{$v->[0]}]}\n") if %{$v->[0]};
      die("element '$e' has subelements\n") if $v->[1] ne '0';
      die("element '$e' must be singleton\n") if exists $out->{$e};
      Encode::_utf8_off($v->[2]) if $bytes;
      $out->{$e} = $v->[2];
    } elsif (@$ke == 1 && !ref($ke->[0])) {
      push @$v, '0', '' if @$v == 1;
      die("element '$e' contains attributes\n") if %{$v->[0]};
      die("element '$e' has subelements\n") if $v->[1] ne '0';
      Encode::_utf8_off($v->[2]) if $bytes;
      push @{$out->{$e}}, $v->[2];
    } else {
      if (@$ke == 1) {
	push @{$out->{$e}}, {};
	_workin($ke->[0], $out->{$e}->[-1], @$v);
      } else {
        die("element '$e' must be singleton\n") if exists $out->{$e};
        $out->{$e} = {};
        _workin($ke, $out->{$e}, @$v);
      }
    }
  }
  if (exists $out->{'_content'}) {
    $out->{'_content'} =~ s/^ //s;
    $out->{'_content'} =~ s/ $//s;
  }
}

sub _escape {
  my ($d) = @_;
  $d =~ s/&/&amp;/sg;
  $d =~ s/</&lt;/sg;
  $d =~ s/>/&gt;/sg;
  $d =~ s/"/&quot;/sg;
  return $d;
}

sub _workout {
  my ($how, $d, $indent) = @_;
  my @how = @$how;
  my $am = _escape(shift @how);
  my $ret = "$indent<$am";
  my $inelem;
  my %d2 = %$d;
  my $gotel = 0;
  if ($am eq '') {
    $ret = '';
    $gotel = $inelem = 1;
    $indent = substr($indent, 2);
  }
  for my $e (@how) {
    if (!$inelem && !ref($e) && $e ne '_content') {
      next unless exists $d2{$e};
      $ret .= _escape(" $e=").'"'._escape($d2{$e}).'"';
      delete $d2{$e};
      next;
    }
    $inelem = 1;
    next if ref($e) && !@$e;	# magic inelem marker
    my $en = $e;
    $en = $en->[0] if ref($en);
    $en = $en->[0] if ref($en);
    next unless exists $d2{$en};
    my $ee = _escape($en);
    if (!ref($e) && $e eq '_content' && !$gotel) {
      $gotel = 2;	# special marker to strip indent
      $ret .= ">"._escape($d2{$e})."\n";
      delete $d2{$e};
      next;
    }
    $ret .= ">\n" unless $gotel;
    $gotel = 1;
    if (!ref($e)) {
      die("'$e' must be scalar\n") if ref($d2{$e});
      if ($e eq '_content') {
	my $c = $d2{$e};
        $ret .= "$indent  "._escape("$c\n");
        delete $d2{$e};
        next;
      }
      if (defined($d2{$e})) {
        $ret .= "$indent  <$ee>"._escape($d2{$e})."</$ee>\n";
      } else {
        $ret .= "$indent  <$ee/>\n";
      }
      delete $d2{$e};
      next;
    } elsif (@$e == 1 && !ref($e->[0])) {
      die("'$en' must be array\n") unless UNIVERSAL::isa($d2{$en}, 'ARRAY');
      for my $se (@{$d2{$en}}) {
        $ret .= "$indent  <$ee>"._escape($se)."</$ee>\n";
      }
      delete $d2{$en};
    } elsif (@$e == 1) {
      die("'$en' must be array\n") unless UNIVERSAL::isa($d2{$en}, 'ARRAY');
      for my $se (@{$d2{$en}}) {
        die("'$en' must be array of hashes\n") unless UNIVERSAL::isa($se, 'HASH');
	$ret .= _workout($e->[0], $se, "$indent  ");
      }
      delete $d2{$en};
    } else {
      die("'$en' must be hash\n") unless UNIVERSAL::isa($d2{$en}, 'HASH');
      $ret .= _workout($e, $d2{$en}, "$indent  ");
      delete $d2{$en};
    }
  }
  die("excess hash entries: ".join(', ', sort keys %d2)."\n") if %d2;
  if ($gotel == 2 && $ret =~ s/\n$//s) {
    $ret .= "</$am>\n" unless $am eq '';
  } elsif ($gotel) {
    $ret .= "$indent</$am>\n" unless $am eq '';
  } else {
    $ret .= " />\n";
  }
  return $ret;
}

package ABStructured::saxparser;

sub new {
  return bless [];
}

sub start_document {
  my ($self) = @_;
  $self->[0] = [];
}

sub start_element {
  my ($self, $e) = @_;
  my %as = map {$_->{'Name'} => $_->{'Value'}} values %{$e->{'Attributes'} || {}};
  push @{$self->[0]}, $e->{'Name'}, [ $self->[0], \%as ];
  $self->[0] = $self->[0]->[-1];
}

sub end_element {
  my ($self) = @_;
  $self->[0] = shift @{$self->[0]};
}

sub characters {
  my ($self, $c)  = @_;

  my $cl = $self->[0];
  if (@$cl > 2 && $cl->[-2] eq '0') {
    $cl->[-1] .= $c->{'Data'};
  } else {
    push @$cl, '0' => $c->{'Data'};
  }
}

sub end_document {
  my ($self) = @_;
  return $self->[0];
}

package ABStructured;

my $xmlinparser;

sub _xmlparser {
  my ($str) = @_;
  my $p = new XML::Parser(Style => 'Tree');
  return $p->parse($str);
}

sub _saxparser {
  my ($str) = @_;
  my $handler = new ABStructured::saxparser;
  my $sp = XML::SAX::ParserFactory->parser('Handler' => $handler);
  if (ref(\$str) eq 'GLOB' || UNIVERSAL::isa($str, 'IO::Handle')) {
    return $sp->parse_file($str);
  }
  return $sp->parse_string($str);
}

sub _chooseparser {
  eval { require XML::SAX; };
  my $saxok;
  if (!$@) {
    $saxok = 1;
    my $parsers = XML::SAX->parsers();
    return \&_saxparser if $parsers && @$parsers && (@$parsers > 1 || $parsers->[0]->{'Name'} ne 'XML::SAX::PurePerl');
  }
  eval { require XML::Parser; };
  return \&_xmlparser unless $@;
  return \&_saxparser if $saxok;
  die("ABStructured needs either XML::SAX or XML::Parser\n");
}

sub XMLin {
  my ($dtd, $str) = @_;
  $xmlinparser = _chooseparser() unless defined $xmlinparser;
  my $d = $xmlinparser->($str);
  my $out = {};
  $d = ['', [{}, @$d]] if $dtd->[0] eq '';
  die("document element must be '$dtd->[0]', was '$d->[0]'\n") if $d->[0] ne $dtd->[0];
  _workin($dtd, $out, @{$d->[1]});
  return $out;
}

sub XMLinfile {
  my ($dtd, $fn) = @_;
  local *F;
  open(F, '<', $fn) || die("$fn: $!\n");
  my $out = XMLin($dtd, *F);
  close F;
  return $out;
}

sub XMLout {
  my ($dtd, $d) = @_;
  die("parameter is not a hash\n") unless UNIVERSAL::isa($d, 'HASH');
  if ($dtd->[0] eq '') {
    die("excess hash elements\n") if keys %$d > 1;
    for my $el (@$dtd) {
      return _workout($el, $d->{$el->[0]}, '') if ref($el) && $d->{$el->[0]};
    }
    die("no match for alternative\n");
  }
  return _workout($dtd, $d, '');
}

1;

__END__

=head1 NAME

ABStructured - simple conversion API from XML to perl structures and back

=head1 SYNOPSIS

    use ABStructured;

    $dtd = [
        'element' =>
            'attribute1',
            'attribute2',
            [],
            'element1',
            [ 'element2' ],
            [ 'element3' =>
                ...
            ],
            [[ 'element4' =>
                ...
            ]],
    ];

    $hashref = XMLin($dtd, $xmlstring);
    $hashref = XMLinfile($dtd, $filename_or_glob);
    $xmlstring = XMLout($dtd, $hashref);

=head1 DESCRIPTION

The ABStructured module provides a way to convert xml data into
a predefined perl data structure and back to xml. Unlike with modules
like XML::Simple it is an error if the xml data does not match
the provided skeleton (the "dtd"). Another advantage is that the
order of the attributes and elements is taken from the dtd when
converting back to xml.

=head2 XMLin()

The XMLin() function takes the dtd and a string as arguments and
returns a hash reference containing the data.

=head2 XMLinfile()

This function works like C<XMLin()>, but takes a filename or a
file descriptor glob as second argument.

=head2 XMLout()

C<XMLout()> provides the reverse operation to C<XMLin()>, it takes
a dtd and a hash reference as arguments and returns an XML string.

=head1 The DTD

The dtd parameter specifies the structure of the allowed xml data.
It consists of nested perl arrays.

=head2 simple attributes and elements

The very simple example for a dtd is:

    $dtd = [ 'user' =>
                 'login',
                 'password',
           ];

This dtd will accept/create XML like:

    <user login="foo" password="bar" />

XMLin doesn't care if "login" or "password" are attributes or
elements, so

    <user>
      <login>foo</login>
      <password>bar</password>
    </user>

is also valid input (but doesn't get re-created by C<XMLout()>).

=head2 multiple elements of the same name

If an element may appear multiple times, it must be declared as
an array in the dtd:

    $dtd = [ 'user' =>
                 'login',
                 [ 'favorite_fruits' ],
           ];

XMLin will create an array reference as value in this case, even if
the xml data contains only one element. Valid XML looks like:

    <user login="foo">
      <favorite_fruits>apple</favorite_fruits>
      <favorite_fruits>peach</favorite_fruits>
    </user>

As attributes may not appear multiple times, XMLout will create
elements for this case. Note also that all attributes must come
before the first element, thus the first array in the dtd ends
the attribute list. As an example, the following dtd

    $dtd = [ 'user' =>
                 'login',
                 [ 'favorite_fruits' ],
                 'password',
           ];

will create xml like:

    <user login="foo">
      <favorite_fruits>apple</favorite_fruits>
      <favorite_fruits>peach</favorite_fruits>
      <password>bar</password>
    </user>

"login" is translated to an attribute and "password" to an element.

You can use an empty array reference to force the end of the attribute
list, e.g.:

    $dtd = [ 'user' =>
                 [],
                 'login',
                 'password',
           ];

will translate to

    <user>
      <login>foo</login>
      <password>bar</password>
    </user>

instead of

    <user login="foo" password="bar" />

=head2 sub-elements

sub-elements are elements that also contain attributes or other
elements. They are specified in the dtd as arrays with more than
one element. Here is an example:

    $dtd = [ 'user' =>
                 'login',
                 [ 'address' =>
                     'street',
                     'city',
                 ],
           ];

Valid xml for this dtd looks like:

    <user login="foo">
      <address street="broadway 7" city="new york" />
    </user>

It is sometimes useful to specify such dtds in multiple steps:

    $addressdtd = [ 'address' =>
                         'street',
                         'city',
                  ];

    $dtd = [ 'user' =>
                 'login',
                 $addressdtd,
           ];

=head2 multiple sub-elements with the same name

As with simple elements, one can allow sub-elements to occur multiple
times. C<XMLin()> creates an array of hash references in this case.
The dtd specification uses an array reference to an array for this
case, for example:

    $dtd = [ 'user' =>
                 'login',
                 [[ 'address' =>
                     'street',
                     'city',
                 ]],
           ];
Or, with the $addressdtd definition used in the previous example:

    $dtd = [ 'user' =>
                 'login',
                 [ $addressdtd ],
           ];

Accepted XML is:

    <user login="foo">
      <address street="broadway 7" city="new york" />
      <address street="rural road 12" city="tempe" />
    </user>

=head2 the _content pseudo-element

All of the non-whitespace parts between elements get collected
into a single "_content" element. As example,

    <user login="foo">
      <address street="broadway 7" city="new york"/>hello
      <address street="rural road 12" city="tempe"/>world
    </user>

would set the _content element to C<hello world> (the dtd must allow
a _content element, of course). If the dtd is

    $dtd = [ 'user' =>
                 'login',
                 [ $addressdtd ],
                 '_content',
           ];

the xml string created by XMLout() will be:

    <user login="foo">
      <address street="broadway 7" city="new york" />
      <address street="rural road 12" city="tempe" />
      hello world    
    </user>

The exact input cannot be re-created, as the positions and the
fragmentation of the content data is lost.

=head1 SEE ALSO

B<ABStructured> requires either L<XML::Parser> or L<XML::SAX>.

=head1 COPYRIGHT 

Copyright 2006 Michael Schroeder E<lt>mls@suse.deE<gt>

This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself. 

=cut

07070100000017000081A40000000000000000000000015C0E85F600002915000000000000000000000000000000000000004A00000000inst-source-utils-2018.12.10/usr/share/inst-source-utils/modules/ABXML.pm
package ABXML;

our $opstatus = [
    'status' =>
	'code',
	[],
	'summary',
	'details',
];

our $patchinfodir = [
  'patchinfodir' =>
	'name',
	[[ 'entry' =>
		'name',
		'md5',
		'status',
		'docu',
	]]
];

our $patchinfo = [
  'patchinfo' =>
	[],
	'Filename',
	'MD5SUM',
	'ISSUEDATE',
	'FILEOWNER',
	'PACKAGER',
	'ARCH',
	'CATEGORY',
	'INDICATIONS',
	'CONTRAINDICATIONS',
	'PRE',
	'POST',
	'ScriptsInline',
	'License',
	'Confirm',
	'UpdateOnlyInstalled',
	'ForceInstall',
	'RebootNeeded',
	'ReloginSuggested',
	'AlwaysInstallPackages',
	'InstallOnly',
	'PATCHFILENAME',
	'LEAVEOLDRPMS',
	'PRE_DE',
	'POST_DE',
	'SUMMARY',
	'SUMMARY_DE',
	'SWAMPID',
	'SUBSWAMPID',
	'SWAMPSTATUS',
	'APPROVED',
	'RATING',
	'BS-REQUESTID',
	[ 'DISTRIBUTION' ],
	[ 'PACKAGE' ],
	[ 'PACKAGE-GA' ],
	[ 'SCRIPT' ],
	[ 'PRESCRIPT' ],
	[ 'POSTSCRIPT' ],
	[ 'CD-Produkt-Name' ],
	[ 'CD-Produkt-Version' ],
	[ 'BUGZILLA' ],
	[ 'CVE' ],
	[ 'UPDATESCRIPT' ],
	[ 'OBSOLETES' ],
	[ 'REQUIRES' ],
	[ 'Freshens' ],
	[ 'IMAGE' ],
	[ 'FILES' ],
	[ 'DESCRIPTION' ],
	[ 'DESCRIPTION_DE' ],
	[ 'DIRECTORIES' ],
];

our $patchdocu = [
    'patchdocu' =>
	[],
	'description',
	'keywords',
	'abstract',
	'swampid',
	'priority',
	'lastchanged',
	[ 'bugzilla' =>
	    [ 'bnum', ]
	],
	[ 'products' =>
	    [[ 'product', =>
		[],
		'name',
		'longname',
		'source',
		'patchname',
	    ]],
	],
	[ 'body', =>
	    [],
	    'html',
	    'ascii',
	    'description',
	],
];

our $approve_pi = [
    'approve_pi' =>
	[],
	'user',
	'behalf',
	'md5sum',
];

our $reject_pi = [
    'reject_pi' =>
	[],
	'user',
	'reason',
	'md5sum',
];

our $maintlist = [
    'maintlist' =>
	[],
	'package',
	'type',
	[ 'DISTRIBUTION' ],
];

our @rpm_entry = (
    [[ 'rpm:entry' =>
	'kind',
	'name',
	'flags',
	'epoch',
	'ver',
	'rel',
	'pre',
    ]],
);

our @rpm_entry_2 = (
    [[ 'rpm:entry' =>
	'kind',
	'name',
	'epoch',
	'ver',
	'rel',
	'pre',
	'flags',
    ]],
);

our @suse_entry = (
    [[ 'suse:entry' =>
	'kind',
	'name',
	'flags',
	'epoch',
	'ver',
	'rel',
	'pre',
    ]],
);

our $repomd =  [
    'repomd' =>
	'xmlns',
	'xmlns:rpm',
	'xmlns:suse',
	[],
	'revision',
	[ 'tags' =>
		[ 'content' ],
		[ 'repo' ],
		[[ 'distro' =>
		    'cpeid',
		    '_content',
		]],
	],
	[[ 'data' =>
		'type',
		[ 'location' =>
		    'href',
		],
		[ 'checksum' =>
		    'type',
		    '_content',
		],
		'timestamp',
		'size',
		'open-size',
		[ 'open-checksum' =>
		    'type',
		    '_content',
		],
	]],
];

our $primary = [
    'metadata' =>
	'xmlns',
	'xmlns:rpm',
	'xmlns:suse',
	'packages',
	[[ 'package' =>
	    'xmlns',
	    'type',
	    [],
	    'name',
	    'arch',
	    [ 'version' =>
		'epoch',
		'ver',
		'rel',
	    ],
	    [[ 'checksum', =>
		'type',
		'pkgid',
		'_content',
	    ]],
	    [[ 'summary' =>
		'lang',
		'_content',
	    ]],
	    [[ 'description' =>
		'lang',
		'_content',
	    ]],
	    'packager',
	    'url',
	    [ 'time' =>
		'file',
		'build',
	    ],
	    [ 'size' =>
		'package',
		'installed',
		'archive',
	    ],
	    [ 'location' =>
		'xml:base',
		'href',
	    ],
	    [ 'format' =>
		[],
		'rpm:license',
		'rpm:vendor',
		'rpm:group',
		'rpm:buildhost',
		'rpm:sourcerpm',
		[ 'rpm:header-range' =>
		    'start',
		    'end',
		],
		[ 'rpm:provides' => @rpm_entry ],
		[ 'rpm:requires' => @rpm_entry ],
		[ 'rpm:conflicts' => @rpm_entry ],
		[ 'rpm:obsoletes' => @rpm_entry ],
		[ 'rpm:suggests' => @rpm_entry ],
		[ 'rpm:recommends' => @rpm_entry ],
		[ 'rpm:supplements' => @rpm_entry ],
		[ 'rpm:enhances' => @rpm_entry ],
		[[ 'file' =>
		    'type',
		    '_content',
		]],
	    ],
	    'suse:license-to-confirm',
	]],
];

our $susedata = [
    'susedata' =>
	'xmlns',
	'packages',
	[[ 'package' =>
	    'pkgid',
	    'name',
	    'arch',
	    [ 'version' =>
		'epoch',
		'ver',
		'rel',
	    ],
	    'eula',
	    'pattern-category',
	    [[ 'keyword' =>
		'_content',
	    ]],
	    [ 'diskusage' =>
		[ 'dirs' =>
		    [[ 'dir' =>
			'name',
			'size',
			'count',
		    ]],
		],
	    ],
	]],
];

our $susedata_i18n = [
    'susedata' =>
	'xmlns',
	'packages',
	[[ 'package' =>
	    'pkgid',
	    'name',
	    'arch',
	    [ 'version' =>
		'epoch',
		'ver',
		'rel',
	    ],
	    [ 'summary' =>
		'lang',
		[],
		'_content',
	    ],
	    [ 'description' =>
		'lang',
		[],
		'_content',
	    ],
	    [ 'pattern-category' =>
		'lang',
		[],
		'_content',
	    ],
	    'eula',
	]],
];

our $filelists = [
    'filelists' =>
        'xmlns',
        'packages',
        [[ 'package' =>
            'pkgid',
            'name',
            'arch',
            [ 'version' =>
                'epoch',
                'ver',
                'rel',
            ],
	    [[ 'file' =>
		'type',
		'_content',
	    ]],
        ]],
];

our $otherdata = [
    'otherdata' =>
        'xmlns',
        'packages',
        [],
        [[ 'package' =>
            'pkgid',
            'name',
            'arch',
            [],
            [ 'version' =>
                'epoch',
                'ver',
                'rel',
            ],
	    [[ 'changelog' =>
		'author',
		'date',
		'_content',
	    ]],
        ]],
];

our $suseinfo = [
    'suseinfo' =>
	'xmlns',
	[],
	'expire',
];

our $patch_zypp = [
    'patch' =>
	'xmlns',
	'xmlns:yum',
	'xmlns:rpm',
	'xmlns:suse',
	'patchid',
	'timestamp',
	'engine',
	[],
	'yum:name',
	[[ 'summary' =>
		'lang',
		'_content',
	]],
	[[ 'description' =>
		'lang',
		'_content',
	]],
	[ 'yum:version' =>
		'ver',
		'rel',
	],
	[ 'rpm:provides' => @rpm_entry_2 ],
	[ 'rpm:requires' => @rpm_entry_2 ],
	[ 'rpm:conflicts' => @rpm_entry_2 ],
	[ 'rpm:obsoletes' => @rpm_entry_2 ],
	[ 'rpm:suggests' => @rpm_entry_2 ],
	[ 'rpm:enhances' => @rpm_entry_2 ],
	[ 'rpm:recommends' => @rpm_entry_2 ],
	[ 'rpm:supplements' => @rpm_entry_2 ],
	'reboot-needed',
	'package-manager',
	'category',
	[ 'update-script' =>
		[],
		'do',
		[ 'do-location' =>
			'href',
		],
		[ 'do-checksum' =>
			'type',
			'_content',
		],
	],
	[[ 'license-to-confirm',
		'lang',
		'_content',
	]],
	[ 'atoms' =>
		[[ 'package' =>
			'xmlns',
			'type',
			[],
			'name',
			'arch',
			[ 'version' =>
				'epoch',
				'ver',
				'rel',
			],
			[[ 'checksum', =>
				'type',
				'pkgid',
				'_content',
			]],
			[ 'time' =>
				'file',
				'build',
			],
			[ 'size' =>
				'package',
				'installed',
				'archive',
			],
			[ 'location' =>
				'xml:base',
				'href',
			],
			[ 'format' =>
				[ 'rpm:provides' => @rpm_entry_2 ],
				[ 'rpm:requires' => @rpm_entry_2 ],
				[ 'rpm:conflicts' => @rpm_entry_2 ],
				[ 'rpm:obsoletes' => @rpm_entry_2 ],
				[ 'rpm:suggests' => @rpm_entry_2 ],
				[ 'rpm:enhances' => @rpm_entry_2 ],
				[ 'rpm:recommends' => @rpm_entry_2 ],
				[ 'rpm:supplements' => @rpm_entry_2 ],
				[ 'suse:freshens' => @suse_entry ],
				'install-only',
			],
			[ 'pkgfiles' =>
				'xmlns',
				[[ 'patchrpm' =>
					[ 'location' =>
						'href',
					],
					[[ 'checksum', =>
						'type',
						'pkgid',
						'_content',
					]],
					[ 'time' =>
						'file',
						'build',
					],
					[ 'size' =>
						'package',
						'installed',
						'archive',
					],
					[[ 'base-version' =>
						'epoch',
						'ver',
						'rel',
					]],
				]],
				[[ 'deltarpm' =>
					[ 'location' =>
						'href',
					],
					[[ 'checksum', =>
						'type',
						'pkgid',
						'_content',
					]],
					[ 'time' =>
						'file',
						'build',
					],
					[ 'size' =>
						'package',
						'installed',
						'archive',
					],
					[ 'base-version' =>
						'epoch',
						'ver',
						'rel',
						'md5sum',
						'buildtime',
						'sequence_info',
					],
				]],
			],
		]],
		[[ 'message' =>
			'xmlns',
			'yum:name',
			[ 'yum:version' =>
				'epoch',
				'ver',
				'rel',
			],
			[ 'text' =>
				'lang',
				'_content',
			],
			[ 'rpm:requires' => 
				'pre',
				@rpm_entry_2 
			],
			[ 'suse:freshens' => @suse_entry ],
		]],
		[[ 'script' =>
			'xmlns',
			'yum:name',
			[ 'yum:version' =>
				'epoch',
				'ver',
				'rel',
			],
			'do',
			[ 'do-location' =>
				'href',
			],
			[ 'do-checksum' =>
				'type',
				'_content',
			],
			[ 'rpm:requires' => 
				'pre',
				@rpm_entry_2 
			],
			[ 'suse:freshens' => @suse_entry ],
		]],
	],
];

our $patch_sat = [
	'update' =>
		'status',
		'from',
		'type',
		'version',
		[],
		'id',
		'title',
		'severity',
		'release',
		[ 'issued' =>
			'date',
		],
		[ 'references' =>
			[[ 'reference' =>
				'href',
				'id',
				'title',
				'type',
			]],
		],
		[ 'description' =>
			'_content',
		],
		[ 'pkglist' =>
			[ 'collection' =>
				[[ 'package' =>
					'name',
					'arch',
					'version',
					'release',
					[],
					'filename',
					'reboot_suggested',
					'relogin_suggested',
					'restart_suggested',
				]],
			],
		],
];

our $bsinfo;

if ($BSXML::request) {
$bsinfo = [
  'bsinfo' =>
      'instance',
      $BSXML::request,
];
};

our $prodfile = [
    'product' =>
	'id',
	'schemeversion',
	[],
	'vendor',
	'name',
	'version',
	'baseversion',
	'patchlevel',
	'migrationtarget',
	'release',
	'arch',
	'endoflife',
	'productline',
	[ 'register' =>
		[],
		'target',
		'release',
		[ 'repositories' =>
			[[ 'repository' =>
				'path',
			]],
		],
	],
        [ 'upgrades' =>
		[],
		[ 'upgrade' =>
			[],
			'name',
			'summary',
			'product',
			'notify',
			'status',
		],
	],
	'updaterepokey',
	'summary',
	'shortsummary',
	'description',
	[ 'linguas' =>
		[[ 'language' => '_content' ]],
	],
	[ 'urls' =>
		[[ 'url' =>
			'name',
			'_content',
		]],
	],
	[ 'buildconfig' =>
		'producttheme',
		'betaversion',
		'allowresolving',
		'mainproduct',
	],
	[ 'installconfig' =>
		'defaultlang',
		'datadir',
		'descriptiondir',
		[],
		[ 'releasepackage' =>
			'name',
			'flag',
			'version',
			'release',
		],
		'distribution',
		[ 'obsoletepackage' ],
	],
	'runtimeconfig',
];

our $productsfile = [
	'products' =>
		[[ 'product' =>
			[],
			'name',
			[ 'version' =>
				'ver',
				'rel',
				'epoch',
			],
			'arch',
			'vendor',
			'summary',
			'description',
		]],
];

our $patchprotocol = [
	'protocol' =>
		[],
		'title',
		'suse',
		'descr',
		[[ 'product' =>
			'name',
			'version',
			'arch',
			'maint',
			[],
			'marketing',
			'path',
			'nppid',
			[[ 'package' =>
				'type',
				'path',
				'name',
			]],
			[[ 'metadata' =>
				'type',
				'cat',
				'path',
				'name',
			]],
		]],
		'had_errors',
];

our $patches = [
	'patches' =>
		'xmlns',
		[[ 'patch' =>
			'id',
			[],
			[ 'checksum' =>
				'type',
				'_content',
			],
			[ 'location' =>
				'href',
			],
			'category',
		]],
];


1;
07070100000018000081A40000000000000000000000015C0E85F600003783000000000000000000000000000000000000004900000000inst-source-utils-2018.12.10/usr/share/inst-source-utils/modules/RPMQ.pm#
# RPMQ.pm -- a simple query API for RPM-files. 
#
# Copyright (C) 2006 Novell Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street,
# Fifth Floor,
# Boston, MA  02110-1301,
# USA.
#
# Revision: $Revision$
#
# ........... mls       all basic query functions,
# 2004-11-24, jw	renamed from RPM.pm to RPMQ.pm to avoid name-clash with cpan modules.
#			added %STAG, the following methods now accept numeric AND symbolic tags:
#			%ref = RPMQ::rpmq_many($file, @tags);
#			@val = RPMQ::rpmq($filename, $tag);
# 2004-11-25, mls       add support for signature header queries

require Data::Dumper;
package RPMQ;

my %STAG = (
        "HEADERIMAGE"	   => 61,
        "HEADERSIGNATURES" => 62,
        "HEADERIMMUTABLE"  => 63,
        "HEADERREGIONS"    => 64,
        "HEADERI18NTABLE"  => 100,
        "SIGSIZE"          => 256+1,
	"SIGLEMD5_1"	   => 256+2,	# /*!< internal - obsolete */
        "SIGPGP"	   => 256+3,
        "SIGLEMD5_2"	   => 256+4,	# /*!< internal - obsolete */
        "SIGMD5" 	   => 256+5,
        "SIGGPG" 	   => 256+6,
        "SIGPGP5"	   => 256+7,	# /*!< internal - obsolete */
        "BADSHA1_1"	   => 256+8,
        "BADSHA1_2"	   => 256+9,
        "PUBKEYS" 	   => 256+10,
        "DSAHEADER" 	   => 256+11,
        "RSAHEADER" 	   => 256+12,
        "SHA1HEADER" 	   => 256+13,

	"SIGTAG_SIZE"      => 1000, 	# /*!< internal Header+Payload size in bytes. */
	"SIGTAG_LEMD5_1"   => 1001, 	# /*!< internal Broken MD5, take 1 @deprecated legacy. */
	"SIGTAG_PGP"       => 1002, 	# /*!< internal PGP 2.6.3 signature. */
	"SIGTAG_LEMD5_2"   => 1003, 	# /*!< internal Broken MD5, take 2 @deprecated legacy. */
	"SIGTAG_MD5"       => 1004, 	# /*!< internal MD5 signature. */
	"SIGTAG_GPG"       => 1005, 	# /*!< internal GnuPG signature. */
	"SIGTAG_PGP5"      => 1006, 	# /*!< internal PGP5 signature @deprecated legacy. */
	"SIGTAG_PAYLOADSIZE" => 1007,	# /*!< internal uncompressed payload size in bytes. */
	"SIGTAG_BADSHA1_1" => 256+8,    # /*!< internal Broken SHA1, take 1. */
	"SIGTAG_BADSHA1_2" => 256+9,    # /*!< internal Broken SHA1, take 2. */
	"SIGTAG_SHA1"      => 256+13,   # /*!< internal sha1 header digest. */
	"SIGTAG_DSA"       => 256+11,   # /*!< internal DSA header signature. */
	"SIGTAG_RSA"       => 256+12,   # /*!< internal RSA header signature. */


        "NAME"		=> 1000,
        "VERSION"	=> 1001,
        "RELEASE"	=> 1002,
        "EPOCH"		=> 1003,
        "SERIAL"	=> 1003,
        "SUMMARY"	=> 1004,
        "DESCRIPTION"	=> 1005,
        "BUILDTIME"	=> 1006,
        "BUILDHOST"	=> 1007,
        "INSTALLTIME"	=> 1008,
        "SIZE"		=> 1009,
        "DISTRIBUTION"	=> 1010,
        "VENDOR"	=> 1011,
        "GIF"		=> 1012,
        "XPM"		=> 1013,
        "LICENSE"	=> 1014,
        "COPYRIGHT"	=> 1014,
        "PACKAGER"	=> 1015,
        "GROUP"		=> 1016,
        "SOURCE"	=> 1018,
        "PATCH"		=> 1019,
        "URL"		=> 1020,
        "OS"		=> 1021,
        "ARCH"		=> 1022,
        "PREIN"		=> 1023,
        "POSTIN"	=> 1024,
        "PREUN"		=> 1025,
        "POSTUN"	=> 1026,
        "OLDFILENAMES"	=> 1027,
        "FILESIZES"	=> 1028,
        "FILESTATES"	=> 1029,
        "FILEMODES"	=> 1030,
        "FILERDEVS"	=> 1033,
        "FILEMTIMES"	=> 1034,
        "FILEMD5S"	=> 1035,
        "FILELINKTOS"	=> 1036,
        "FILEFLAGS"	=> 1037,
        "FILEUSERNAME"	=> 1039,
        "FILEGROUPNAME"	=> 1040,
        "ICON"		=> 1043,
        "SOURCERPM"	=> 1044,
        "FILEVERIFYFLAGS"	=> 1045,
        "ARCHIVESIZE"	=> 1046,
        "PROVIDENAME"	=> 1047,
        "PROVIDES"	=> 1047,
        "REQUIREFLAGS"	=> 1048,
        "REQUIRENAME"	=> 1049,
        "REQUIREVERSION"	=> 1050,
        "NOSOURCE"	=> 1051,
        "NOPATCH"	=> 1052,
        "CONFLICTFLAGS"	=> 1053,
        "CONFLICTNAME"	=> 1054,
        "CONFLICTVERSION"	=> 1055,
        "EXCLUDEARCH"	=> 1059,
        "EXCLUDEOS"	=> 1060,
        "EXCLUSIVEARCH"	=> 1061,
        "EXCLUSIVEOS"	=> 1062,
        "RPMVERSION"	=> 1064,
        "TRIGGERSCRIPTS"	=> 1065,
        "TRIGGERNAME"	=> 1066,
        "TRIGGERVERSION"	=> 1067,
        "TRIGGERFLAGS"	=> 1068,
        "TRIGGERINDEX"	=> 1069,
        "VERIFYSCRIPT"	=> 1079,
        "CHANGELOGTIME"	=> 1080,
        "CHANGELOGNAME"	=> 1081,
        "CHANGELOGTEXT"	=> 1082,
        "PREINPROG"	=> 1085,
        "POSTINPROG"	=> 1086,
        "PREUNPROG"	=> 1087,
        "POSTUNPROG"	=> 1088,
        "BUILDARCHS"	=> 1089,
        "OBSOLETENAME"	=> 1090,
        "OBSOLETES"	=> 1090,
        "VERIFYSCRIPTPROG"	=> 1091,
        "TRIGGERSCRIPTPROG"	=> 1092,
        "COOKIE"	=> 1094,
        "FILEDEVICES"	=> 1095,
        "FILEINODES"	=> 1096,
        "FILELANGS"	=> 1097,
        "PREFIXES"	=> 1098,
        "INSTPREFIXES"	=> 1099,
        "SOURCEPACKAGE"	=> 1106,
        "PROVIDEFLAGS"	=> 1112,
        "PROVIDEVERSION"	=> 1113,
        "OBSOLETEFLAGS"	=> 1114,
        "OBSOLETEVERSION"	=> 1115,
        "DIRINDEXES"	=> 1116,
        "BASENAMES"	=> 1117,
        "DIRNAMES"	=> 1118,
        "OPTFLAGS"	=> 1122,
        "DISTURL"	=> 1123,
        "PAYLOADFORMAT"	=> 1124,
        "PAYLOADCOMPRESSOR"	=> 1125,
        "PAYLOADFLAGS"	=> 1126,
        "INSTALLCOLOR"	=> 1127,
        "INSTALLTID"	=> 1128,
        "REMOVETID"	=> 1129,
        "RHNPLATFORM"	=> 1131,
        "PLATFORM"	=> 1132,
        "PATCHESNAME"	=> 1133,
        "PATCHESFLAGS"	=> 1134,
        "PATCHESVERSION"	=> 1135,
        "CACHECTIME"	=> 1136,
        "CACHEPKGPATH"	=> 1137,
        "CACHEPKGSIZE"	=> 1138,
        "CACHEPKGMTIME"	=> 1139,
        "FILECOLORS"	=> 1140,
        "FILECLASS"	=> 1141,
        "CLASSDICT"	=> 1142,
        "FILEDEPENDSX"	=> 1143,
        "FILEDEPENDSN"	=> 1144,
        "DEPENDSDICT"	=> 1145,
        "SOURCEPKGID"	=> 1146,
        "PRETRANS"	=> 1151,
        "POSTTRANS"	=> 1152,
        "PRETRANSPROG"	=> 1153,
        "POSTTRANSPROG"	=> 1154,
        "DISTTAG"	=> 1155,
	"SUGGESTSNAME"	=> 1156,
	"SUGGESTSVERSION"	=> 1157,
	"SUGGESTSFLAGS"		=> 1158,
	"ENHANCESNAME"	=> 1159,
	"ENHANCESVERSION"	=> 1160,
	"ENHANCESFLAGS"		=> 1161,
	"FILEDIGESTALGOS"	=> 1177,
	"FILEDIGESTALGO"	=> 5011,
);

sub RPMSENSE_MISSINGOK () { 0x80000 }
sub RPMSENSE_STRONG    () { 0x8000000 }

sub rpmpq {
  my $rpm = shift;
  local *RPM;

  return undef unless open(RPM, "< $rpm");
  my $head;
  if (sysread(RPM, $head, 75) < 11) {
    close RPM;
    return undef;
  }
  close RPM;
  my $name = unpack('@10Z65', $head);
  return $name if length($name) < 65;
  my %q = rpmq_many($rpm, 'NAME', 'VERSION', 'RELEASE');
  return "$q{'NAME'}->[0]-$q{'VERSION'}->[0]-$q{'RELEASE'}->[0]";
}

sub rpmq {
  my $rpm = shift;
  my $stag = shift;

  my %ret = rpmq_many($rpm, $stag);
  return @{$ret{$stag} || [undef]};
}

# do not mix numeric tags with symbolic tags.
# special symbolic tag 'FILENAME' exists.
sub rpmq_many {
  my $rpm = shift;
  my @stags = @_;

  my @sigtags = grep {/^SIGTAG_/} @stags;
  @stags = grep {!/^SIGTAG_/} @stags;
  my $dosigs = @sigtags && !@stags;
  @stags = @sigtags if $dosigs;

  my %vtags = map {$_ => 1} @stags;
  my $need_filenames = $vtags{'FILENAMES'};
  push @stags, 'BASENAMES', 'DIRNAMES', 'DIRINDEXES', 'OLDFILENAMES' if $need_filenames;
  @stags = grep { $_ ne 'FILENAMES' } @stags if $need_filenames;
  my %stags = map {0+($STAG{$_} or $_) => $_} @stags;

  my ($magic, $sigtype, $headmagic, $cnt, $cntdata, $lead, $head, $index, $data, $tag, $type, $offset, $count);

  local *RPM;
  if (ref($rpm) eq 'ARRAY') {
    ($headmagic, $cnt, $cntdata) = unpack('N@8NN', $rpm->[0]);
    if ($headmagic != 0x8eade801) {
      warn("Bad rpm\n");
      return ();
    }
    if (length($rpm->[0]) < 16 + $cnt * 16 + $cntdata) {
      warn("Bad rpm\n");
      return ();
    }
    $index = substr($rpm->[0], 16, $cnt * 16);
    $data = substr($rpm->[0], 16 + $cnt * 16, $cntdata);
  } else {
    if (ref($rpm) eq 'GLOB') {
      *RPM = $rpm;
    } elsif (!open(RPM, "<$rpm")) {
      warn("$rpm: $!\n");
      return ();
    }
    if (read(RPM, $lead, 96) != 96) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
    ($magic, $sigtype) = unpack('N@78n', $lead);
    if ($magic != 0xedabeedb || $sigtype != 5) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
    if (read(RPM, $head, 16) != 16) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
    ($headmagic, $cnt, $cntdata) = unpack('N@8NN', $head);
    if ($headmagic != 0x8eade801) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
    if (read(RPM, $index, $cnt * 16) != $cnt * 16) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
    $cntdata = ($cntdata + 7) & ~7;
    if (read(RPM, $data, $cntdata) != $cntdata) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
  }

  my %res = ();

  if (@sigtags && !$dosigs) {
    %res = &rpmq_many(["$head$index$data"], @sigtags);
  }
  if (ref($rpm) eq 'ARRAY' && !$dosigs && @stags && @$rpm > 1) {
    my %res2 = &rpmq_many([ $rpm->[1] ], @stags);
    %res = (%res, %res2);
    return %res;
  }

  if ($vtags{'HEADERSTART'}) {
    $res{'HEADERSTART'} = [ 96 + 16 + 16 * $cnt + $cntdata ];
  }

  if (ref($rpm) ne 'ARRAY' && !$dosigs && @stags) {
    if (read(RPM, $head, 16) != 16) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
    ($headmagic, $cnt, $cntdata) = unpack('N@8NN', $head);
    if ($headmagic != 0x8eade801) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
    if (read(RPM, $index, $cnt * 16) != $cnt * 16) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
    if (read(RPM, $data, $cntdata) != $cntdata) {
      warn("Bad rpm $rpm\n");
      close RPM;
      return ();
    }
  }
  if ($vtags{'HEADEREND'}) {
    $res{'HEADEREND'} = ($res{'HEADERSTART'} || 0) + 16 + 16 * $cnt + $cntdata;
    @stags = grep {$_ ne 'HEADERSTART' && $_ ne 'HEADEREND'} @stags;
  }
  if ($vtags{'EXTRA'}) {
    my $offset = 96 + 16 + 16 * $cnt + $cntdata;
    my $extradata;
    read(RPM, $extradata, 1024, $offset);
    chomp($extradata);
    my %extras = map{split /\:/, $_}(split / /, $extradata);
    $res{'EXTRA'} = [\%extras];
    close RPM;
  }
  close RPM if ref($rpm) ne 'ARRAY';

  return %res unless @stags;	# nothing to do

  while($cnt-- > 0) {
    ($tag, $type, $offset, $count, $index) = unpack('N4a*', $index);
    $tag = 0+$tag;
    if ($stags{$tag}) {
      eval {
        my $otag = $stags{$tag};
	if ($type == 0) {
	  $res{$otag} = [ '' ];
	} elsif ($type == 1) {
	  $res{$otag} = [ unpack("\@${offset}c$count", $data) ];
	} elsif ($type == 2) {
	  $res{$otag} = [ unpack("\@${offset}c$count", $data) ];
	} elsif ($type == 3) {
	  $res{$otag} = [ unpack("\@${offset}n$count", $data) ];
	} elsif ($type == 4) {
	  $res{$otag} = [ unpack("\@${offset}N$count", $data) ];
	} elsif ($type == 5) {
	  $res{$otag} = [ undef ];
	} elsif ($type == 6) {
	  $res{$otag} = [ unpack("\@${offset}Z*", $data) ];
	} elsif ($type == 7) {
	  $res{$otag} = [ unpack("\@${offset}a$count", $data) ];
	} elsif ($type == 8 || $type == 9) {
	  my $d = unpack("\@${offset}a*", $data);
	  my @res = split("\0", $d, $count + 1);
	  $res{$otag} = [ splice @res, 0, $count ];
	} else {
	  $res{$otag} = [ undef ];
	}
      };
      if ($@) {
	warn("Bad rpm $rpm: $@\n");
        return ();
      }
    }
  }
  
  if ($need_filenames) {
    if ($res{'OLDFILENAMES'}) {
      $res{'FILENAMES'} = [ @{$res{'OLDFILENAMES'}} ];
    } else {
      my $i = 0;
      $res{'FILENAMES'} = [ map {"$res{'DIRNAMES'}->[$res{'DIRINDEXES'}->[$i++]]$_"} @{$res{'BASENAMES'}} ];
    }
  }
  return %res;
}

sub rpmq_add_flagsvers {
  my $res = shift;
  my $name = shift;
  my $flags = shift;
  my $vers = shift;
  my $addx = shift;

  return unless $res;
  my @flags = @{$res->{$flags} || []};
  my @vers = @{$res->{$vers} || []};
  for (@{$res->{$name}}) {
    $_ = "?$_" if $addx && $flags[0] & 0x80000;
    $_ = "#$_" if $addx && $flags[0] & 0x8000000;
    if (@flags && ($flags[0] & 0xe) && @vers) {
      $_ .= ' ';
      $_ .= '<' if $flags[0] & 2;
      $_ .= '>' if $flags[0] & 4;
      $_ .= '=' if $flags[0] & 8;
      $_ .= " $vers[0]";
    }
    shift @flags;
    shift @vers;
  }
}

sub rpmq_provreq {
  my $rpm = shift;

  my @prov = ();
  my @req = ();
  my $r;
  my %res = rpmq_many($rpm, 1047, 1049, 1048, 1050, 1112, 1113);
  rpmq_add_flagsvers(\%res, 1047, 1112, 1113);
  rpmq_add_flagsvers(\%res, 1049, 1048, 1050);
  return $res{1047}, $res{1049};
}

1;

__END__

=head1 NAME

RPMQ - a simple query-API for RPM-files

=head1 SYNOPSIS

	use RPMQ;

        $rpmname = RPMQ::rpmpq($rpmfile);		# returns "name-version-rel"
	%r = RPMQ::rpmq_many($rpmfile, @tags);		# returns hash of array-refs
	@v = RPMQ::rpmq($rpmfile, $tag);		# returns array-ref

	($prov, $req) = RPMQ::rpmq_provreq($rpmfile);	# returns 2 array-refs

        %r = RPMQ::rpmq_many($rpmfile, qw{REQUIRENAME REQUIREFLAGS REQUIREVERSION});
  	RPMQ::rpmq_add_flagsvers(\%r,  qw{REQUIRENAME REQUIREFLAGS REQUIREVERSION});
	print join "\n", @{$r{REQUIRENAME}}, "";
	
  
=head1 DESCRIPTION

Common tag names are: 
        "NAME"		=> 1000,
        "VERSION"	=> 1001,
        "RELEASE"	=> 1002,
        "SUMMARY"	=> 1004,
        "DESCRIPTION"	=> 1005,
        "BUILDTIME"	=> 1006,
        "BUILDHOST"	=> 1007,
        "SIZE"		=> 1009,
        "COPYRIGHT"	=> 1014,
        "ARCH"		=> 1022,
        "SOURCERPM"	=> 1044,
        "DISTURL"	=> 1123,

The additional tag 'FILENAMES' is also understood by rpmq_many() and
rpmq(). It returns a list of full filenames (like OLDFILENAMES did in
rpm3) constructed from DIRNAMES, DIRINDEXES and BASENAMES.

=cut
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!395 blocks