diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | EXPERIMENTAL | 0 | ||||
-rw-r--r-- | README.md | 88 | ||||
-rw-r--r-- | REFLECTION | 335 | ||||
-rw-r--r-- | config.m4 | 25 | ||||
-rw-r--r-- | examples/librpm.php | 68 | ||||
-rw-r--r-- | package.xml | 277 | ||||
-rw-r--r-- | php_rpminfo.h | 22 | ||||
-rw-r--r-- | rpminfo.c | 757 | ||||
-rw-r--r-- | rpminfo.stub.php | 17 | ||||
-rw-r--r-- | rpminfo_arginfo.h | 60 | ||||
-rw-r--r-- | tests/002-rpmvercmp.phpt | 95 | ||||
-rw-r--r-- | tests/003-rpminfo.phpt | 2 | ||||
-rw-r--r-- | tests/005-rpminfo-full.phpt | 6 | ||||
-rw-r--r-- | tests/006-rpminfo-errors.phpt | 8 | ||||
-rw-r--r-- | tests/007-rpmdbinfo.phpt | 30 | ||||
-rw-r--r-- | tests/008-rpmdbsearch.phpt | 67 | ||||
-rw-r--r-- | tests/009-rpmdbinfo2.phpt | 22 | ||||
-rw-r--r-- | tests/011-rpmvercmp_error8.phpt | 37 | ||||
-rw-r--r-- | tests/012-rpmaddtag.phpt | 16 | ||||
-rw-r--r-- | tests/013-rpmdbsearch-error.phpt | 16 | ||||
-rw-r--r-- | tests/014-stream.phpt | 97 | ||||
-rw-r--r-- | tests/bidon.rpm | bin | 6972 -> 7599 bytes | |||
-rw-r--r-- | tests/bidon.spec | 42 |
24 files changed, 1903 insertions, 187 deletions
@@ -1,6 +1,7 @@ # Object files *.o *.lo +*.dep # Libraries *.lib @@ -26,12 +27,14 @@ config.cache config.guess config.h config.h.in +config.h.in~ config.log config.nice config.status config.sub configure configure.in +configure.ac conftest conftest.c Makefile diff --git a/EXPERIMENTAL b/EXPERIMENTAL deleted file mode 100644 index e69de29..0000000 --- a/EXPERIMENTAL +++ /dev/null @@ -2,7 +2,11 @@ Retrieve RPM information from PHP code using librpm. -**Notice**: this is a experimental extension, a work in progress, so don't expect a stable API yet. +This extension can be considered as stable, and be used on production environement. + +But be aware that if its API will probably stay stable, +some changes may occur before version 1.0.0. + ---- @@ -97,8 +101,86 @@ The return value is an array of hash tables, or false if it fails. [0] => Array ( [Name] => php - [Version] => 7.2.2 - [Release] => 1.fc27.remi + [Version] => 7.3.5 + [Release] => 1.fc31.remi + [Summary] => PHP scripting language for creating dynamic web sites + [Arch] => x86_64 + ) + ) + +Retrieve information from rpm database about installed packages using glob or regex. +The return value is an array of hash tables, or false if it fails. + + $ php -a + php > print_r(rpmdbsearch("php-pecl-r*", RPMTAG_NAME, RPMMIRE_GLOB)); + Array + ( + [0] => Array + ( + [Name] => php-pecl-radius + [Version] => 1.4.0 + [Release] => 0.10.b1.fc31 + [Summary] => Radius client library + [Arch] => x86_64 + ) + [1] => Array + ( + [Name] => php-pecl-redis5 + [Version] => 5.2.0 + [Release] => 1.fc31.remi.7.3 + [Summary] => Extension for communicating with the Redis key-value store + [Arch] => x86_64 + ) + [2] => Array + ( + [Name] => php-pecl-rpminfo + [Version] => 0.2.3 + [Release] => 1.fc31.remi.7.3 + [Summary] => RPM information + [Arch] => x86_64 + ) + ) + + $ php -a + php > print_r(rpmdbsearch("^php-pecl-r", RPMTAG_NAME, RPMMIRE_REGEX)); + Array + ( + [0] => Array + ( + [Name] => php-pecl-radius + [Version] => 1.4.0 + [Release] => 0.10.b1.fc31 + [Summary] => Radius client library + [Arch] => x86_64 + ) + [1] => Array + ( + [Name] => php-pecl-redis5 + [Version] => 5.2.0 + [Release] => 1.fc31.remi.7.3 + [Summary] => Extension for communicating with the Redis key-value store + [Arch] => x86_64 + ) + [2] => Array + ( + [Name] => php-pecl-rpminfo + [Version] => 0.2.3 + [Release] => 1.fc31.remi.7.3 + [Summary] => RPM information + [Arch] => x86_64 + ) + ) + + $ php -a + php > print_r(rpmdbsearch(PHP_BINARY, RPMTAG_INSTFILENAMES)); + Array + ( + [0] => Array + ( + [Name] => php-cli + [Version] => 7.3.15 + [Release] => 1.fc31.remi + [Summary] => Command-line interface for PHP [Arch] => x86_64 ) ) @@ -1,54 +1,321 @@ -Extension [ <persistent> extension #129 rpminfo version 0.2.1 ] { - - - Constants [24] { - Constant [ string RPMVERSION ] { 4.14.1 } - Constant [ integer RPMSENSE_ANY ] { 0 } - Constant [ integer RPMSENSE_LESS ] { 2 } - Constant [ integer RPMSENSE_GREATER ] { 4 } - Constant [ integer RPMSENSE_EQUAL ] { 8 } - Constant [ integer RPMSENSE_POSTTRANS ] { 32 } - Constant [ integer RPMSENSE_PREREQ ] { 64 } - Constant [ integer RPMSENSE_PRETRANS ] { 128 } - Constant [ integer RPMSENSE_INTERP ] { 256 } - Constant [ integer RPMSENSE_SCRIPT_PRE ] { 512 } - Constant [ integer RPMSENSE_SCRIPT_POST ] { 1024 } - Constant [ integer RPMSENSE_SCRIPT_PREUN ] { 2048 } - Constant [ integer RPMSENSE_SCRIPT_POSTUN ] { 4096 } - Constant [ integer RPMSENSE_SCRIPT_VERIFY ] { 8192 } - Constant [ integer RPMSENSE_FIND_REQUIRES ] { 16384 } - Constant [ integer RPMSENSE_FIND_PROVIDES ] { 32768 } - Constant [ integer RPMSENSE_TRIGGERIN ] { 65536 } - Constant [ integer RPMSENSE_TRIGGERUN ] { 131072 } - Constant [ integer RPMSENSE_TRIGGERPOSTUN ] { 262144 } - Constant [ integer RPMSENSE_MISSINGOK ] { 524288 } - Constant [ integer RPMSENSE_RPMLIB ] { 16777216 } - Constant [ integer RPMSENSE_TRIGGERPREIN ] { 33554432 } - Constant [ integer RPMSENSE_KEYRING ] { 67108864 } - Constant [ integer RPMSENSE_CONFIG ] { 268435456 } +Extension [ <persistent> extension #15 rpminfo version 0.5.0 ] { + + - Constants [271] { + Constant [ string RPMVERSION ] { 4.15.1 } + Constant [ int RPMSENSE_ANY ] { 0 } + Constant [ int RPMSENSE_LESS ] { 2 } + Constant [ int RPMSENSE_GREATER ] { 4 } + Constant [ int RPMSENSE_EQUAL ] { 8 } + Constant [ int RPMSENSE_POSTTRANS ] { 32 } + Constant [ int RPMSENSE_PREREQ ] { 64 } + Constant [ int RPMSENSE_PRETRANS ] { 128 } + Constant [ int RPMSENSE_INTERP ] { 256 } + Constant [ int RPMSENSE_SCRIPT_PRE ] { 512 } + Constant [ int RPMSENSE_SCRIPT_POST ] { 1024 } + Constant [ int RPMSENSE_SCRIPT_PREUN ] { 2048 } + Constant [ int RPMSENSE_SCRIPT_POSTUN ] { 4096 } + Constant [ int RPMSENSE_SCRIPT_VERIFY ] { 8192 } + Constant [ int RPMSENSE_FIND_REQUIRES ] { 16384 } + Constant [ int RPMSENSE_FIND_PROVIDES ] { 32768 } + Constant [ int RPMSENSE_TRIGGERIN ] { 65536 } + Constant [ int RPMSENSE_TRIGGERUN ] { 131072 } + Constant [ int RPMSENSE_TRIGGERPOSTUN ] { 262144 } + Constant [ int RPMSENSE_MISSINGOK ] { 524288 } + Constant [ int RPMSENSE_RPMLIB ] { 16777216 } + Constant [ int RPMSENSE_TRIGGERPREIN ] { 33554432 } + Constant [ int RPMSENSE_KEYRING ] { 67108864 } + Constant [ int RPMSENSE_CONFIG ] { 268435456 } + Constant [ int RPMMIRE_DEFAULT ] { 0 } + Constant [ int RPMMIRE_STRCMP ] { 1 } + Constant [ int RPMMIRE_REGEX ] { 2 } + Constant [ int RPMMIRE_GLOB ] { 3 } + Constant [ int RPMTAG_ARCH ] { 1022 } + Constant [ int RPMTAG_ARCHIVESIZE ] { 1046 } + Constant [ int RPMTAG_BASENAMES ] { 1117 } + Constant [ int RPMTAG_BUGURL ] { 5012 } + Constant [ int RPMTAG_BUILDARCHS ] { 1089 } + Constant [ int RPMTAG_BUILDHOST ] { 1007 } + Constant [ int RPMTAG_BUILDTIME ] { 1006 } + Constant [ int RPMTAG_C ] { 1054 } + Constant [ int RPMTAG_CHANGELOGNAME ] { 1081 } + Constant [ int RPMTAG_CHANGELOGTEXT ] { 1082 } + Constant [ int RPMTAG_CHANGELOGTIME ] { 1080 } + Constant [ int RPMTAG_CLASSDICT ] { 1142 } + Constant [ int RPMTAG_CONFLICTFLAGS ] { 1053 } + Constant [ int RPMTAG_CONFLICTNAME ] { 1054 } + Constant [ int RPMTAG_CONFLICTNEVRS ] { 5044 } + Constant [ int RPMTAG_CONFLICTS ] { 1054 } + Constant [ int RPMTAG_CONFLICTVERSION ] { 1055 } + Constant [ int RPMTAG_COOKIE ] { 1094 } + Constant [ int RPMTAG_DBINSTANCE ] { 1195 } + Constant [ int RPMTAG_DEPENDSDICT ] { 1145 } + Constant [ int RPMTAG_DESCRIPTION ] { 1005 } + Constant [ int RPMTAG_DIRINDEXES ] { 1116 } + Constant [ int RPMTAG_DIRNAMES ] { 1118 } + Constant [ int RPMTAG_DISTRIBUTION ] { 1010 } + Constant [ int RPMTAG_DISTTAG ] { 1155 } + Constant [ int RPMTAG_DISTURL ] { 1123 } + Constant [ int RPMTAG_DSAHEADER ] { 267 } + Constant [ int RPMTAG_E ] { 1003 } + Constant [ int RPMTAG_ENCODING ] { 5062 } + Constant [ int RPMTAG_ENHANCEFLAGS ] { 5057 } + Constant [ int RPMTAG_ENHANCENAME ] { 5055 } + Constant [ int RPMTAG_ENHANCENEVRS ] { 5061 } + Constant [ int RPMTAG_ENHANCES ] { 5055 } + Constant [ int RPMTAG_ENHANCEVERSION ] { 5056 } + Constant [ int RPMTAG_EPOCH ] { 1003 } + Constant [ int RPMTAG_EPOCHNUM ] { 5019 } + Constant [ int RPMTAG_EVR ] { 5013 } + Constant [ int RPMTAG_EXCLUDEARCH ] { 1059 } + Constant [ int RPMTAG_EXCLUDEOS ] { 1060 } + Constant [ int RPMTAG_EXCLUSIVEARCH ] { 1061 } + Constant [ int RPMTAG_EXCLUSIVEOS ] { 1062 } + Constant [ int RPMTAG_FILECAPS ] { 5010 } + Constant [ int RPMTAG_FILECLASS ] { 1141 } + Constant [ int RPMTAG_FILECOLORS ] { 1140 } + Constant [ int RPMTAG_FILECONTEXTS ] { 1147 } + Constant [ int RPMTAG_FILEDEPENDSN ] { 1144 } + Constant [ int RPMTAG_FILEDEPENDSX ] { 1143 } + Constant [ int RPMTAG_FILEDEVICES ] { 1095 } + Constant [ int RPMTAG_FILEDIGESTALGO ] { 5011 } + Constant [ int RPMTAG_FILEDIGESTS ] { 1035 } + Constant [ int RPMTAG_FILEFLAGS ] { 1037 } + Constant [ int RPMTAG_FILEGROUPNAME ] { 1040 } + Constant [ int RPMTAG_FILEINODES ] { 1096 } + Constant [ int RPMTAG_FILELANGS ] { 1097 } + Constant [ int RPMTAG_FILELINKTOS ] { 1036 } + Constant [ int RPMTAG_FILEMD5S ] { 1035 } + Constant [ int RPMTAG_FILEMODES ] { 1030 } + Constant [ int RPMTAG_FILEMTIMES ] { 1034 } + Constant [ int RPMTAG_FILENAMES ] { 5000 } + Constant [ int RPMTAG_FILENLINKS ] { 5045 } + Constant [ int RPMTAG_FILEPROVIDE ] { 5001 } + Constant [ int RPMTAG_FILERDEVS ] { 1033 } + Constant [ int RPMTAG_FILEREQUIRE ] { 5002 } + Constant [ int RPMTAG_FILESIGNATURELENGTH ] { 5091 } + Constant [ int RPMTAG_FILESIGNATURES ] { 5090 } + Constant [ int RPMTAG_FILESIZES ] { 1028 } + Constant [ int RPMTAG_FILESTATES ] { 1029 } + Constant [ int RPMTAG_FILETRIGGERCONDS ] { 5086 } + Constant [ int RPMTAG_FILETRIGGERFLAGS ] { 5072 } + Constant [ int RPMTAG_FILETRIGGERINDEX ] { 5070 } + Constant [ int RPMTAG_FILETRIGGERNAME ] { 5069 } + Constant [ int RPMTAG_FILETRIGGERPRIORITIES ] { 5084 } + Constant [ int RPMTAG_FILETRIGGERSCRIPTFLAGS ] { 5068 } + Constant [ int RPMTAG_FILETRIGGERSCRIPTPROG ] { 5067 } + Constant [ int RPMTAG_FILETRIGGERSCRIPTS ] { 5066 } + Constant [ int RPMTAG_FILETRIGGERTYPE ] { 5087 } + Constant [ int RPMTAG_FILETRIGGERVERSION ] { 5071 } + Constant [ int RPMTAG_FILEUSERNAME ] { 1039 } + Constant [ int RPMTAG_FILEVERIFYFLAGS ] { 1045 } + Constant [ int RPMTAG_FSCONTEXTS ] { 1148 } + Constant [ int RPMTAG_GIF ] { 1012 } + Constant [ int RPMTAG_GROUP ] { 1016 } + Constant [ int RPMTAG_HDRID ] { 269 } + Constant [ int RPMTAG_HEADERCOLOR ] { 5017 } + Constant [ int RPMTAG_HEADERI18NTABLE ] { 100 } + Constant [ int RPMTAG_HEADERIMAGE ] { 61 } + Constant [ int RPMTAG_HEADERIMMUTABLE ] { 63 } + Constant [ int RPMTAG_HEADERREGIONS ] { 64 } + Constant [ int RPMTAG_HEADERSIGNATURES ] { 62 } + Constant [ int RPMTAG_ICON ] { 1043 } + Constant [ int RPMTAG_INSTALLCOLOR ] { 1127 } + Constant [ int RPMTAG_INSTALLTID ] { 1128 } + Constant [ int RPMTAG_INSTALLTIME ] { 1008 } + Constant [ int RPMTAG_INSTFILENAMES ] { 5040 } + Constant [ int RPMTAG_INSTPREFIXES ] { 1099 } + Constant [ int RPMTAG_LICENSE ] { 1014 } + Constant [ int RPMTAG_LONGARCHIVESIZE ] { 271 } + Constant [ int RPMTAG_LONGFILESIZES ] { 5008 } + Constant [ int RPMTAG_LONGSIGSIZE ] { 270 } + Constant [ int RPMTAG_LONGSIZE ] { 5009 } + Constant [ int RPMTAG_MODULARITYLABEL ] { 5096 } + Constant [ int RPMTAG_N ] { 1000 } + Constant [ int RPMTAG_NAME ] { 1000 } + Constant [ int RPMTAG_NEVR ] { 5015 } + Constant [ int RPMTAG_NEVRA ] { 5016 } + Constant [ int RPMTAG_NOPATCH ] { 1052 } + Constant [ int RPMTAG_NOSOURCE ] { 1051 } + Constant [ int RPMTAG_NVR ] { 5014 } + Constant [ int RPMTAG_NVRA ] { 1196 } + Constant [ int RPMTAG_O ] { 1090 } + Constant [ int RPMTAG_OBSOLETEFLAGS ] { 1114 } + Constant [ int RPMTAG_OBSOLETENAME ] { 1090 } + Constant [ int RPMTAG_OBSOLETENEVRS ] { 5043 } + Constant [ int RPMTAG_OBSOLETES ] { 1090 } + Constant [ int RPMTAG_OBSOLETEVERSION ] { 1115 } + Constant [ int RPMTAG_OLDENHANCES ] { 1159 } + Constant [ int RPMTAG_OLDENHANCESFLAGS ] { 1161 } + Constant [ int RPMTAG_OLDENHANCESNAME ] { 1159 } + Constant [ int RPMTAG_OLDENHANCESVERSION ] { 1160 } + Constant [ int RPMTAG_OLDFILENAMES ] { 1027 } + Constant [ int RPMTAG_OLDSUGGESTS ] { 1156 } + Constant [ int RPMTAG_OLDSUGGESTSFLAGS ] { 1158 } + Constant [ int RPMTAG_OLDSUGGESTSNAME ] { 1156 } + Constant [ int RPMTAG_OLDSUGGESTSVERSION ] { 1157 } + Constant [ int RPMTAG_OPTFLAGS ] { 1122 } + Constant [ int RPMTAG_ORDERFLAGS ] { 5037 } + Constant [ int RPMTAG_ORDERNAME ] { 5035 } + Constant [ int RPMTAG_ORDERVERSION ] { 5036 } + Constant [ int RPMTAG_ORIGBASENAMES ] { 1120 } + Constant [ int RPMTAG_ORIGDIRINDEXES ] { 1119 } + Constant [ int RPMTAG_ORIGDIRNAMES ] { 1121 } + Constant [ int RPMTAG_ORIGFILENAMES ] { 5007 } + Constant [ int RPMTAG_OS ] { 1021 } + Constant [ int RPMTAG_P ] { 1047 } + Constant [ int RPMTAG_PACKAGER ] { 1015 } + Constant [ int RPMTAG_PATCH ] { 1019 } + Constant [ int RPMTAG_PATCHESFLAGS ] { 1134 } + Constant [ int RPMTAG_PATCHESNAME ] { 1133 } + Constant [ int RPMTAG_PATCHESVERSION ] { 1135 } + Constant [ int RPMTAG_PAYLOADCOMPRESSOR ] { 1125 } + Constant [ int RPMTAG_PAYLOADDIGEST ] { 5092 } + Constant [ int RPMTAG_PAYLOADDIGESTALGO ] { 5093 } + Constant [ int RPMTAG_PAYLOADFLAGS ] { 1126 } + Constant [ int RPMTAG_PAYLOADFORMAT ] { 1124 } + Constant [ int RPMTAG_PKGID ] { 261 } + Constant [ int RPMTAG_PLATFORM ] { 1132 } + Constant [ int RPMTAG_POLICIES ] { 1150 } + Constant [ int RPMTAG_POLICYFLAGS ] { 5033 } + Constant [ int RPMTAG_POLICYNAMES ] { 5030 } + Constant [ int RPMTAG_POLICYTYPES ] { 5031 } + Constant [ int RPMTAG_POLICYTYPESINDEXES ] { 5032 } + Constant [ int RPMTAG_POSTIN ] { 1024 } + Constant [ int RPMTAG_POSTINFLAGS ] { 5021 } + Constant [ int RPMTAG_POSTINPROG ] { 1086 } + Constant [ int RPMTAG_POSTTRANS ] { 1152 } + Constant [ int RPMTAG_POSTTRANSFLAGS ] { 5025 } + Constant [ int RPMTAG_POSTTRANSPROG ] { 1154 } + Constant [ int RPMTAG_POSTUN ] { 1026 } + Constant [ int RPMTAG_POSTUNFLAGS ] { 5023 } + Constant [ int RPMTAG_POSTUNPROG ] { 1088 } + Constant [ int RPMTAG_PREFIXES ] { 1098 } + Constant [ int RPMTAG_PREIN ] { 1023 } + Constant [ int RPMTAG_PREINFLAGS ] { 5020 } + Constant [ int RPMTAG_PREINPROG ] { 1085 } + Constant [ int RPMTAG_PRETRANS ] { 1151 } + Constant [ int RPMTAG_PRETRANSFLAGS ] { 5024 } + Constant [ int RPMTAG_PRETRANSPROG ] { 1153 } + Constant [ int RPMTAG_PREUN ] { 1025 } + Constant [ int RPMTAG_PREUNFLAGS ] { 5022 } + Constant [ int RPMTAG_PREUNPROG ] { 1087 } + Constant [ int RPMTAG_PROVIDEFLAGS ] { 1112 } + Constant [ int RPMTAG_PROVIDENAME ] { 1047 } + Constant [ int RPMTAG_PROVIDENEVRS ] { 5042 } + Constant [ int RPMTAG_PROVIDES ] { 1047 } + Constant [ int RPMTAG_PROVIDEVERSION ] { 1113 } + Constant [ int RPMTAG_PUBKEYS ] { 266 } + Constant [ int RPMTAG_R ] { 1002 } + Constant [ int RPMTAG_RECOMMENDFLAGS ] { 5048 } + Constant [ int RPMTAG_RECOMMENDNAME ] { 5046 } + Constant [ int RPMTAG_RECOMMENDNEVRS ] { 5058 } + Constant [ int RPMTAG_RECOMMENDS ] { 5046 } + Constant [ int RPMTAG_RECOMMENDVERSION ] { 5047 } + Constant [ int RPMTAG_RECONTEXTS ] { 1149 } + Constant [ int RPMTAG_RELEASE ] { 1002 } + Constant [ int RPMTAG_REMOVETID ] { 1129 } + Constant [ int RPMTAG_REQUIREFLAGS ] { 1048 } + Constant [ int RPMTAG_REQUIRENAME ] { 1049 } + Constant [ int RPMTAG_REQUIRENEVRS ] { 5041 } + Constant [ int RPMTAG_REQUIRES ] { 1049 } + Constant [ int RPMTAG_REQUIREVERSION ] { 1050 } + Constant [ int RPMTAG_RPMVERSION ] { 1064 } + Constant [ int RPMTAG_RSAHEADER ] { 268 } + Constant [ int RPMTAG_SHA1HEADER ] { 269 } + Constant [ int RPMTAG_SHA256HEADER ] { 273 } + Constant [ int RPMTAG_SIGGPG ] { 262 } + Constant [ int RPMTAG_SIGMD5 ] { 261 } + Constant [ int RPMTAG_SIGPGP ] { 259 } + Constant [ int RPMTAG_SIGSIZE ] { 257 } + Constant [ int RPMTAG_SIZE ] { 1009 } + Constant [ int RPMTAG_SOURCE ] { 1018 } + Constant [ int RPMTAG_SOURCEPACKAGE ] { 1106 } + Constant [ int RPMTAG_SOURCEPKGID ] { 1146 } + Constant [ int RPMTAG_SOURCERPM ] { 1044 } + Constant [ int RPMTAG_SUGGESTFLAGS ] { 5051 } + Constant [ int RPMTAG_SUGGESTNAME ] { 5049 } + Constant [ int RPMTAG_SUGGESTNEVRS ] { 5059 } + Constant [ int RPMTAG_SUGGESTS ] { 5049 } + Constant [ int RPMTAG_SUGGESTVERSION ] { 5050 } + Constant [ int RPMTAG_SUMMARY ] { 1004 } + Constant [ int RPMTAG_SUPPLEMENTFLAGS ] { 5054 } + Constant [ int RPMTAG_SUPPLEMENTNAME ] { 5052 } + Constant [ int RPMTAG_SUPPLEMENTNEVRS ] { 5060 } + Constant [ int RPMTAG_SUPPLEMENTS ] { 5052 } + Constant [ int RPMTAG_SUPPLEMENTVERSION ] { 5053 } + Constant [ int RPMTAG_TRANSFILETRIGGERCONDS ] { 5088 } + Constant [ int RPMTAG_TRANSFILETRIGGERFLAGS ] { 5082 } + Constant [ int RPMTAG_TRANSFILETRIGGERINDEX ] { 5080 } + Constant [ int RPMTAG_TRANSFILETRIGGERNAME ] { 5079 } + Constant [ int RPMTAG_TRANSFILETRIGGERPRIORITIES ] { 5085 } + Constant [ int RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS ] { 5078 } + Constant [ int RPMTAG_TRANSFILETRIGGERSCRIPTPROG ] { 5077 } + Constant [ int RPMTAG_TRANSFILETRIGGERSCRIPTS ] { 5076 } + Constant [ int RPMTAG_TRANSFILETRIGGERTYPE ] { 5089 } + Constant [ int RPMTAG_TRANSFILETRIGGERVERSION ] { 5081 } + Constant [ int RPMTAG_TRIGGERCONDS ] { 5005 } + Constant [ int RPMTAG_TRIGGERFLAGS ] { 1068 } + Constant [ int RPMTAG_TRIGGERINDEX ] { 1069 } + Constant [ int RPMTAG_TRIGGERNAME ] { 1066 } + Constant [ int RPMTAG_TRIGGERSCRIPTFLAGS ] { 5027 } + Constant [ int RPMTAG_TRIGGERSCRIPTPROG ] { 1092 } + Constant [ int RPMTAG_TRIGGERSCRIPTS ] { 1065 } + Constant [ int RPMTAG_TRIGGERTYPE ] { 5006 } + Constant [ int RPMTAG_TRIGGERVERSION ] { 1067 } + Constant [ int RPMTAG_URL ] { 1020 } + Constant [ int RPMTAG_V ] { 1001 } + Constant [ int RPMTAG_VCS ] { 5034 } + Constant [ int RPMTAG_VENDOR ] { 1011 } + Constant [ int RPMTAG_VERBOSE ] { 5018 } + Constant [ int RPMTAG_VERIFYSCRIPT ] { 1079 } + Constant [ int RPMTAG_VERIFYSCRIPTFLAGS ] { 5026 } + Constant [ int RPMTAG_VERIFYSCRIPTPROG ] { 1091 } + Constant [ int RPMTAG_VERSION ] { 1001 } + Constant [ int RPMTAG_XPM ] { 1013 } } - Functions { + Function [ <internal:rpminfo> function rpmaddtag ] { + + - Parameters [1] { + Parameter #0 [ <required> int $rpmtag ] + } + - Return [ bool ] + } Function [ <internal:rpminfo> function rpmdbinfo ] { - Parameters [2] { - Parameter #0 [ <required> $name ] - Parameter #1 [ <optional> $full ] + Parameter #0 [ <required> string $nevr ] + Parameter #1 [ <optional> bool $full ] + } + - Return [ array or NULL ] + } + Function [ <internal:rpminfo> function rpmdbsearch ] { + + - Parameters [4] { + Parameter #0 [ <required> string $pattern ] + Parameter #1 [ <optional> int $rpmtag ] + Parameter #2 [ <optional> int $rpmmire ] + Parameter #3 [ <optional> bool $full ] } + - Return [ array or NULL ] } Function [ <internal:rpminfo> function rpminfo ] { - Parameters [3] { - Parameter #0 [ <required> $path ] - Parameter #1 [ <optional> $full ] - Parameter #2 [ <optional> &$error ] + Parameter #0 [ <required> string $path ] + Parameter #1 [ <optional> bool $full ] + Parameter #2 [ <optional> string or NULL &$error ] } + - Return [ array or NULL ] } Function [ <internal:rpminfo> function rpmvercmp ] { - Parameters [2] { - Parameter #0 [ <required> $evr1 ] - Parameter #1 [ <required> $evr2 ] + Parameter #0 [ <required> string $evr1 ] + Parameter #1 [ <required> string $evr2 ] } + - Return [ int ] } } } @@ -4,26 +4,19 @@ PHP_ARG_ENABLE(rpminfo, whether to enable rpminfo support, [ --enable-rpminfo Enable rpminfo support]) if test "$PHP_RPMINFO" != "no"; then - dnl Write more examples of tests here... - AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + PKG_CHECK_MODULES([LIBRPM], [rpm >= 4.11.3]) - AC_MSG_CHECKING(for librpm) - if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists rpm; then - if $PKG_CONFIG rpm --atleast-version 4.11.3; then - LIBRPM_CFLAGS=`$PKG_CONFIG rpm --cflags` - LIBRPM_LIBDIR=`$PKG_CONFIG rpm --libs` - LIBRPM_VERSON=`$PKG_CONFIG rpm --modversion` - AC_MSG_RESULT(from pkgconfig: version $LIBRPM_VERSON) - else - AC_MSG_ERROR(system librpm is too old: version 4.11.3 required) - fi - else - AC_MSG_ERROR(pkg-config not found) - fi - PHP_EVAL_LIBLINE($LIBRPM_LIBDIR, RPMINFO_SHARED_LIBADD) + PHP_EVAL_LIBLINE($LIBRPM_LIBS, RPMINFO_SHARED_LIBADD) PHP_EVAL_INCLINE($LIBRPM_CFLAGS) + AC_MSG_CHECKING(for rpm >= 4.13) + PKG_CHECK_EXISTS([rpm >= 4.13], + AC_DEFINE(HAVE_ARCHIVE, 1, [ Archive reader since RPM 4.13 ]) + AC_DEFINE(HAVE_WEAKDEP, 1, [ Indexes on weak dependency field since RPM 4.13 ]) + AC_MSG_RESULT([yes]), AC_MSG_RESULT([no]) + ) + PHP_SUBST(RPMINFO_SHARED_LIBADD) PHP_NEW_EXTENSION(rpminfo, rpminfo.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) diff --git a/examples/librpm.php b/examples/librpm.php index 7d36f2d..6ae8b81 100644 --- a/examples/librpm.php +++ b/examples/librpm.php @@ -59,22 +59,47 @@ abstract class Common { if (isset($this->info['Requirename'])) { return $this->_dep($this->info['Requirename'], $this->info['Requireflags'], $this->info['Requireversion']); } + return NULL; case 'Conflicts': if (isset($this->info['Conflictname'])) { return $this->_dep($this->info['Conflictname'], $this->info['Conflictflags'], $this->info['Conflictversion']); } + return NULL; case 'Obsoletes': if (isset($this->info['Obsoletename'])) { return $this->_dep($this->info['Obsoletename'], $this->info['Obsoleteflags'], $this->info['Obsoleteversion']); } + return NULL; case 'Provides': if (isset($this->info['Providename'])) { return $this->_dep($this->info['Providename'], $this->info['Provideflags'], $this->info['Provideversion']); } + return NULL; + case 'Recommends': + if (isset($this->info['Recommendname'])) { + return $this->_dep($this->info['Recommendname'], $this->info['Recommendflags'], $this->info['Recommendversion']); + } + return NULL; + case 'Suggests': + if (isset($this->info['Suggestname'])) { + return $this->_dep($this->info['Suggestname'], $this->info['Suggestflags'], $this->info['Suggestversion']); + } + return NULL; + case 'Supplements': + if (isset($this->info['Supplementname'])) { + return $this->_dep($this->info['Supplementname'], $this->info['Supplementflags'], $this->info['Supplementversion']); + } + return NULL; + case 'Enhances': + if (isset($this->info['Enhancename'])) { + return $this->_dep($this->info['Enhancename'], $this->info['Enhanceflags'], $this->info['Enhanceversion']); + } + return NULL; case 'Files': if (isset($this->info['Basenames'])) { return $this->_files(); } + return NULL; default: if (isset($this->info[$name])) { return $this->info[$name]; @@ -94,7 +119,7 @@ abstract class Common { class File extends Common { public function __construct($path) { - $info = rpminfo($path, true, $error); + $info = \rpminfo($path, true, $error); if ($error) { throw new \RuntimeException($error); @@ -114,7 +139,7 @@ class File extends Common { class Package extends Common { public function __construct($name, $index=0) { - $info = rpmdbinfo($name, true); + $info = \rpmdbinfo($name, true); if (!$info) { throw new \RuntimeException("$name not found"); @@ -126,8 +151,47 @@ class Package extends Common { } } +/** + * Find packages which provides something or own a file + * + * $a = \Remi\RPM\WhatProvides("php-redis"); + * print_r($a[0]->NEVR); + * + * $a = \Remi\RPM\WhatProvides("/usr/bin/php"); + * print_r($a[0]->NEVR); + **/ +function WhatProvides($crit) { + if (file_exists($crit)) { + $a = \rpmdbsearch($crit, RPMTAG_INSTFILENAMES); + } else { + $a = \rpmdbsearch($crit, RPMTAG_PROVIDES); + } + $r = []; + if (is_array($a)) { + foreach($a as $i) { + $r[] = new Package($i['Name']); + } + } + return $r; +} +/** + * Find packages which requires something + * + * $a = \Remi\RPM\WhatRequires("php-common"); + * print_r($a[0]->NEVRA); + **/ +function WhatRequires($crit) { + $a = \rpmdbsearch($crit, RPMTAG_REQUIRES); + $r = []; + if (is_array($a)) { + foreach($a as $i) { + $r[] = new Package($i['Name']); + } + } + return $r; +} /* $a = new File(dirname(__DIR__).'/tests/bidon.rpm'); $a = new Package('phpunit7'); diff --git a/package.xml b/package.xml index 3d0ddec..ff6a59e 100644 --- a/package.xml +++ b/package.xml @@ -3,11 +3,9 @@ <name>rpminfo</name> <channel>pecl.php.net</channel> <summary>RPM information</summary> - <description>Retrieve RPM information using librpm. -Available functions: -- rpmvercmp to compare 2 EVRs -- rpminfo to retrieve information from a RPM file -- rpmdbinfo to rerieve information from an installed RPM + <description>Retrieve RPM information using librpm, from local RPM file or from installed packages database. + +Documentation: https://www.php.net/rpminfo </description> <lead> <name>Remi Collet</name> @@ -15,20 +13,19 @@ Available functions: <email>remi@php.net</email> <active>yes</active> </lead> - <date>2018-02-12</date> + <date>2023-11-10</date> <version> - <release>0.2.1</release> - <api>0.2.0</api> + <release>1.1.1dev</release> + <api>1.1.0</api> </version> <stability> - <release>beta</release> - <api>beta</api> + <release>stable</release> + <api>stable</api> </stability> - <license>PHP 3.01</license> + <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license> <notes> -- add summary in minimal information set -- retrieve array from metadata -- add RPMSENSE_* macros +- check open_basedir restriction +- new function: rpmgetsymlink(string $path, string $name): ?string </notes> <contents> <dir name="/"> @@ -36,9 +33,10 @@ Available functions: <file name="config.m4" role="src"/> <file name="php_rpminfo.h" role="src" /> <file name="rpminfo.c" role="src"/> + <file name="rpminfo.stub.php" role="src"/> + <file name="rpminfo_arginfo.h" role="src"/> <!-- documentation --> <file name="CREDITS" role="doc"/> - <file name="EXPERIMENTAL" role="doc"/> <file name="LICENSE" role="doc"/> <file name="README.md" role="doc"/> <dir name ="examples"> @@ -54,6 +52,12 @@ Available functions: <file name="005-rpminfo-full.phpt" role="test"/> <file name="006-rpminfo-errors.phpt" role="test"/> <file name="007-rpmdbinfo.phpt" role="test"/> + <file name="008-rpmdbsearch.phpt" role="test"/> + <file name="009-rpmdbinfo2.phpt" role="test"/> + <file name="011-rpmvercmp_error8.phpt" role="test"/> + <file name="012-rpmaddtag.phpt" role="test"/> + <file name="013-rpmdbsearch-error.phpt" role="test"/> + <file name="014-stream.phpt" role="test"/> <file name="bidon.rpm" role="test"/> <file name="bidon-src.rpm" role="test"/> </dir> @@ -62,7 +66,7 @@ Available functions: <dependencies> <required> <php> - <min>7.0.0</min> + <min>8.0.0</min> </php> <pearinstaller> <min>1.10.0</min> @@ -73,6 +77,247 @@ Available functions: <extsrcrelease/> <changelog> <release> + <date>2023-11-10</date> + <version> + <release>1.1.0</release> + <api>1.1.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license> + <notes> +- check open_basedir restriction +- new function: rpmgetsymlink(string $path, string $name): ?string + </notes> + </release> + <release> + <date>2023-10-13</date> + <version> + <release>1.0.1</release> + <api>1.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license> + <notes> +- fix stack smashing on 32-bit +- allow retrieval of hardlink content + </notes> + </release> + <release> + <date>2023-10-12</date> + <version> + <release>1.0.0</release> + <api>1.0.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license> + <notes> +- implement rpm stream wrapper with librpm >= 4.13 + </notes> + </release> + <release> + <date>2023-09-26</date> + <version> + <release>0.7.0</release> + <api>0.7.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license> + <notes> +- add optional operator to rpmcmpver for consistency with version_compare +- drop support for PHP 7 + </notes> + </release> + <release> + <date>2021-06-18</date> + <version> + <release>0.6.0</release> + <api>0.5.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license> + <notes> +- generate arginfo from stub and add missing default values +- raise dependency on PHP 7.2 +- raise exception on bad parameter value with PHP 8 + </notes> + </release> + <release> + <date>2020-09-23</date> + <version> + <release>0.5.1</release> + <api>0.5.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>PHP 3.01</license> + <notes> +- split tests for PHP 7/8 +- improve librpm example + </notes> + </release> + <release> + <date>2020-04-07</date> + <version> + <release>0.5.0</release> + <api>0.5.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>PHP 3.01</license> + <notes> +- add rpmaddtag() function + </notes> + </release> + <release> + <date>2020-03-25</date> + <version> + <release>0.4.2</release> + <api>0.4.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>PHP 3.01</license> + <notes> +- improve reflection with better parameter names +- speed optimization: open DB only once per request + </notes> + </release> + <release> + <date>2020-03-18</date> + <version> + <release>0.4.1</release> + <api>0.4.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>PHP 3.01</license> + <notes> +- fix build with RPM 4.12 (Fedora 21-22 only) +- add type hinting in reflection +- return NULL instead of FALSE on failure + </notes> + </release> + <release> + <date>2020-03-13</date> + <version> + <release>0.4.0</release> + <api>0.4.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license>PHP 3.01</license> + <notes> +- improve search logic, use index when exists and no search mode +- add 'full' parameter to rpmdbsearch +- allow 'rpmdbinfo' to search on NEVR (instead of name only) +- first "stable" release + </notes> + </release> + <release> + <date>2020-03-12</date> + <version> + <release>0.3.1</release> + <api>0.3.0</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>PHP 3.01</license> + <notes> +- allow search by Pkgid, Hdrid, Installtid with specific input +- fix search with various other tags (Version, ...) + </notes> + </release> + <release> + <date>2020-03-12</date> + <version> + <release>0.3.0</release> + <api>0.3.0</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>PHP 3.01</license> + <notes> +- add rpmdbsearch function to search packages using + name, installed files, requires, provides... + </notes> + </release> + <release> + <date>2020-03-11</date> + <version> + <release>0.2.3</release> + <api>0.2.0</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>PHP 3.01</license> + <notes> +- fix gh#2 free allocated iterators to avoid "DB2053 Freeing read locks..." messages + </notes> + </release> + <release> + <date>2020-03-11</date> + <version> + <release>0.2.2</release> + <api>0.2.0</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>PHP 3.01</license> + <notes> +- Fix gh#1 rpmvercmp() incorrect comparison result + </notes> + </release> + <release> + <date>2018-02-12</date> + <version> + <release>0.2.1</release> + <api>0.2.0</api> + </version> + <stability> + <release>beta</release> + <api>beta</api> + </stability> + <license>PHP 3.01</license> + <notes> +- add summary in minimal information set +- retrieve array from metadata +- add RPMSENSE_* macros + </notes> + </release> + <release> <date>2018-02-08</date> <version> <release>0.2.0</release> diff --git a/php_rpminfo.h b/php_rpminfo.h index 6516139..ddc912f 100644 --- a/php_rpminfo.h +++ b/php_rpminfo.h @@ -1,8 +1,8 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | rpminfo extension for PHP | +----------------------------------------------------------------------+ - | Copyright (c) 2018 The PHP Group | + | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -22,22 +22,20 @@ extern zend_module_entry rpminfo_module_entry; #define phpext_rpminfo_ptr &rpminfo_module_entry -#define PHP_RPMINFO_VERSION "0.2.1" - -#ifdef PHP_WIN32 -# define PHP_RPMINFO_API __declspec(dllexport) -#elif defined(__GNUC__) && __GNUC__ >= 4 -# define PHP_RPMINFO_API __attribute__ ((visibility("default"))) -#else -# define PHP_RPMINFO_API -#endif +#define PHP_RPMINFO_VERSION "1.1.1-dev" +#define PHP_RPMINFO_AUTHOR "Remi Collet" +#define PHP_RPMINFO_LICENSE "PHP-3.01" #ifdef ZTS #include "TSRM.h" #endif ZEND_BEGIN_MODULE_GLOBALS(rpminfo) - rpmts ts; + rpmts ts; /* transaction set */ + rpmdb db; /* database */ + int nb_tags; /* stored tags */ + int max_tags; /* allocated tags */ + rpmTagVal *tags; /* tags storage */ ZEND_END_MODULE_GLOBALS(rpminfo) #define RPMINFO_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(rpminfo, v) @@ -1,8 +1,8 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | rpminfo extension for PHP | +----------------------------------------------------------------------+ - | Copyright (c) 2018 The PHP Group | + | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -23,6 +23,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" +#include "ext/standard/php_string.h" #include <fcntl.h> #include <rpm/rpmdb.h> @@ -32,44 +33,78 @@ #include "php_rpminfo.h" +#include "rpminfo_arginfo.h" + +#ifdef HAVE_ARCHIVE +struct php_rpm_stream_data_t { + FD_t gzdi; + Header h; + rpmfiles files; + rpmfi fi; + php_stream *stream; +}; + +#define STREAM_DATA_FROM_STREAM() \ + struct php_rpm_stream_data_t *self = (struct php_rpm_stream_data_t *) stream->abstract; +#endif + ZEND_DECLARE_MODULE_GLOBALS(rpminfo) -static rpmts rpminfo_getts(rpmVSFlags flags) { +static rpmts rpminfo_getts(void) { if (!RPMINFO_G(ts)) { rpmReadConfigFiles(NULL, NULL); RPMINFO_G(ts) = rpmtsCreate(); } if (RPMINFO_G(ts)) { - (void)rpmtsSetVSFlags(RPMINFO_G(ts), flags); + (void)rpmtsSetVSFlags(RPMINFO_G(ts), _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | RPMVSF_NOHDRCHK); } return RPMINFO_G(ts); } +static rpmdb rpminfo_getdb(void) { + if (!RPMINFO_G(db)) { + rpmts ts = rpminfo_getts(); + + rpmtsOpenDB(ts, O_RDONLY); + RPMINFO_G(db) = rpmtsGetRdb(ts); + } + return RPMINFO_G(db); +} + static void rpm_header_to_zval(zval *return_value, Header h, zend_bool full) { HeaderIterator hi; rpmTagVal tag; rpmTagType type; const char *val; + int i; array_init(return_value); hi = headerInitIterator(h); while ((tag=headerNextTag(hi)) != RPMTAG_NOT_FOUND) { - switch (tag) { - case RPMTAG_NAME: - case RPMTAG_VERSION: - case RPMTAG_RELEASE: - case RPMTAG_EPOCH: - case RPMTAG_ARCH: - case RPMTAG_SUMMARY: - break; - default: - if (!full) { - continue; - } + if (!full) { + switch (tag) { + case RPMTAG_NAME: + case RPMTAG_VERSION: + case RPMTAG_RELEASE: + case RPMTAG_EPOCH: + case RPMTAG_ARCH: + case RPMTAG_SUMMARY: + /* Always present tags */ + break; + default: + /* Additional tags */ + for (i=0 ; i<RPMINFO_G(nb_tags) ; i++) { + if (tag == RPMINFO_G(tags)[i]) { + break; + } + } + if (i==RPMINFO_G(nb_tags)) { + continue; + } + } } - //printf("Tag: %-30s Type: %8lx - %8lx - %8lx\n", rpmTagGetName(tag), (long)rpmTagGetTagType(tag), (long)rpmTagGetType(tag), (long)rpmTagGetReturnType(tag)); type = rpmTagGetTagType(tag); switch (type) { case RPM_STRING_TYPE: @@ -174,17 +209,12 @@ static void rpm_header_to_zval(zval *return_value, Header h, zend_bool full) } } } + headerFreeIterator(hi); if (full) { add_assoc_bool(return_value, "IsSource", headerIsSource(h)); } } -ZEND_BEGIN_ARG_INFO_EX(arginfo_rpminfo, 0, 0, 1) - ZEND_ARG_INFO(0, path) - ZEND_ARG_INFO(0, full) - ZEND_ARG_INFO(1, error) -ZEND_END_ARG_INFO() - /* {{{ proto array rpminfo(string path [, bool full [, string &$error]) Retrieve information from a RPM file */ PHP_FUNCTION(rpminfo) @@ -195,16 +225,19 @@ PHP_FUNCTION(rpminfo) zval *error = NULL; FD_t f; Header h; - rpmts ts = rpminfo_getts(_RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | RPMVSF_NOHDRCHK); + rpmts ts = rpminfo_getts(); if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|bz", &path, &len, &full, &error) == FAILURE) { - return; + RETURN_THROWS(); } if (error) { ZVAL_DEREF(error); zval_dtor(error); ZVAL_NULL(error); } + if (php_check_open_basedir(path)) { + RETURN_NULL(); + } f = Fopen(path, "r"); if (f) { @@ -239,17 +272,12 @@ PHP_FUNCTION(rpminfo) } efree(e_msg); } - RETURN_FALSE; + RETURN_NULL(); } /* }}} */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_rpmdbinfo, 0, 0, 1) - ZEND_ARG_INFO(0, name) - ZEND_ARG_INFO(0, full) -ZEND_END_ARG_INFO() - -/* {{{ proto array rpmdbinfo(string name [, bool full [, string &$error]) - Retrieve information from a RPM file */ +/* {{{ proto array rpmdbinfo(string nevr [, bool full]) + Retrieve information from an installed RPM */ PHP_FUNCTION(rpmdbinfo) { char *name; @@ -258,17 +286,16 @@ PHP_FUNCTION(rpmdbinfo) Header h; rpmdb db; rpmdbMatchIterator di; - rpmts ts = rpminfo_getts(_RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | RPMVSF_NOHDRCHK); if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|b", &name, &len, &full) == FAILURE) { - return; + RETURN_THROWS(); } - rpmtsOpenDB(ts, O_RDONLY); - db = rpmtsGetRdb(ts); - di = rpmdbInitIterator(db, RPMTAG_NAME, name, len); + db = rpminfo_getdb(); + di = rpmdbInitIterator(db, RPMDBI_LABEL, name, len); if (!di) { - RETURN_FALSE; + /* Not found */ + RETURN_NULL(); } array_init(return_value); @@ -277,33 +304,583 @@ PHP_FUNCTION(rpmdbinfo) rpm_header_to_zval(&tmp, h, full); add_next_index_zval(return_value, &tmp); } + + rpmdbFreeIterator(di); } /* }}} */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_rpmvercmp, 0, 0, 2) - ZEND_ARG_INFO(0, evr1) - ZEND_ARG_INFO(0, evr2) -ZEND_END_ARG_INFO() +static unsigned char nibble(char c) { + if (c >= '0' && c <= '9') { + return (c - '0'); + } + if (c >= 'a' && c <= 'f') { + return (c - 'a') + 10; + } + if (c >= 'A' && c <= 'F') { + return (c - 'A') + 10; + } + return 0; +} + +static int hex2bin(const char *hex, char *bin, int len) { + int i; + + for (i=0 ; (i+1)<len ; i+=2, hex+=2, bin++) { + *bin = nibble(hex[0]) << 4 | nibble(hex[1]); + } + + return i/2; +} + +static int haveIndex(zend_long tag) { + /* + All DB indexes + excepted RPMDBI_PACKAGES and RPMDBI_LABEL doesn't match any tag + */ + if (tag == RPMDBI_NAME || + tag == RPMDBI_BASENAMES || + tag == RPMDBI_GROUP || + tag == RPMDBI_REQUIRENAME || + tag == RPMDBI_PROVIDENAME || + tag == RPMDBI_CONFLICTNAME || + tag == RPMDBI_OBSOLETENAME || + tag == RPMDBI_TRIGGERNAME || + tag == RPMDBI_DIRNAMES || + tag == RPMDBI_INSTALLTID || + tag == RPMDBI_SIGMD5 || + tag == RPMDBI_SHA1HEADER || +#ifdef HAVE_WEAKDEP + tag == RPMDBI_FILETRIGGERNAME || + tag == RPMDBI_TRANSFILETRIGGERNAME || + tag == RPMDBI_RECOMMENDNAME || + tag == RPMDBI_SUGGESTNAME || + tag == RPMDBI_SUPPLEMENTNAME || + tag == RPMDBI_ENHANCENAME || +#endif + tag == RPMDBI_INSTFILENAMES) { + return 1; + } + return 0; +} + +/* {{{ proto array rpmdbsearch(string pattern [, integer tag_name = RPMTAG_NAME [, integer mode = -1 [, bool full = 0]]]) + Search information from installed RPMs */ +PHP_FUNCTION(rpmdbsearch) +{ + char MD5[16]; + rpm_tid_t tid; + char *name; + size_t len; + zend_long crit = RPMTAG_NAME; + zend_long mode = -1; + zend_bool full = 0; + Header h; + rpmdb db; + rpmdbMatchIterator di; + int useIndex = 1; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|llb", &name, &len, &crit, &mode, &full) == FAILURE) { + RETURN_THROWS(); + } + if (rpmTagGetType(crit) == RPM_NULL_TYPE) { + zend_argument_value_error(2, "Unkown rpmtag"); + RETURN_THROWS(); + } + if (mode != RPMMIRE_DEFAULT && + mode != RPMMIRE_STRCMP && + mode != RPMMIRE_REGEX && + mode != RPMMIRE_GLOB && + mode != -1) { + zend_argument_value_error(3, "Unkown rpmmire"); + RETURN_THROWS(); + } + + if (crit == RPMTAG_PKGID) { + if (len != 32) { + zend_argument_value_error(1, "Bad length for PKGID, 32 expected"); + RETURN_THROWS(); + } + len = hex2bin(name, MD5, len); + name = MD5; + } else if (crit == RPMTAG_HDRID) { + if (len != 40) { + zend_argument_value_error(1, "Bad length for HDRID, 40 expected"); + RETURN_THROWS(); + } + } else if (crit == RPMTAG_INSTALLTID) { + tid = atol(name); + name = (char *)&tid; + len = sizeof(tid); + } else if (crit == RPMTAG_INSTFILENAMES) { + /* use input parameters */ + } else { + /* Faster mode if index exists and name is not a pattern */ + useIndex = haveIndex(crit) && mode < 0; + } + + db = rpminfo_getdb(); + if (useIndex) { + /* Simple criterion using index */ + di = rpmdbInitIterator(db, crit, name, len); + } else { + /* query all packages */ + di = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0); + /* add criterion */ + if (di) { + if (rpmdbSetIteratorRE(di, crit, (mode<0 ? RPMMIRE_DEFAULT : mode), name)) { + php_error_docref(NULL, E_WARNING, "Can't set filter"); + RETURN_NULL(); + } + } + } + if (!di) { + /* Not found */ + RETURN_NULL(); + } + + array_init_size(return_value, rpmdbGetIteratorCount(di)); + while ((h = rpmdbNextIterator(di)) != NULL) { + zval tmp; + rpm_header_to_zval(&tmp, h, full); + add_next_index_zval(return_value, &tmp); + } + + rpmdbFreeIterator(di); +} +/* }}} */ /* {{{ proto int rpmcmpver(string evr1, string evr2) - Compare 2 RPM evr (epoch:version-release) strings */ + Compare 2 RPM EVRs (epoch:version-release) strings */ PHP_FUNCTION(rpmvercmp) { - char *evr1, *evr2; - size_t len1, len2; + char *in_evr1, *evr1, *v1, *r1; + char *in_evr2, *evr2, *v2, *r2; + char *p, empty[] = ""; + char *op = NULL; + long e1, e2, r; + size_t len1, len2, oplen; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|s", &in_evr1, &len1, &in_evr2, &len2, &op, &oplen) == FAILURE) { + RETURN_THROWS(); + } + evr1 = estrdup(in_evr1); + evr2 = estrdup(in_evr2); + + /* Epoch */ + p = strchr(evr1, ':'); + if (p) { + v1 = p+1; + *p=0; + e1 = atol(evr1); + } else { + v1 = evr1; + e1 = 0; + } + p = strchr(evr2, ':'); + if (p) { + v2 = p+1; + *p=0; + e2 = atol(evr2); + } else { + v2 = evr2; + e2 = 0; + } + if (e1 < e2) { + r = -1; + } else if (e1 > e2) { + r = 1; + } else { + /* Version */ + p = strchr(v1, '-'); + if (p) { + r1 = p+1; + *p = 0; + } else { + r1 = empty; + } + p = strchr(v2, '-'); + if (p) { + r2 = p+1; + *p = 0; + } else { + r2 = empty; + } + r = rpmvercmp(v1, v2); + if (!r) { + /* Release*/ + r = rpmvercmp(r1, r2); + } + } + efree(evr1); + efree(evr2); + + if (!op) { + RETURN_LONG(r); + } + + if (!strcmp(op, "<") || !strcmp(op, "lt")) { + RETURN_BOOL(r < 0); + } + if (!strcmp(op, "<=") || !strcmp(op, "le")) { + RETURN_BOOL(r <= 0); + } + if (!strcmp(op, ">") || !strcmp(op, "gt")) { + RETURN_BOOL(r > 0); + } + if (!strcmp(op, ">=") || !strcmp(op, "ge")) { + RETURN_BOOL(r >= 0); + } + if (!strcmp(op, "==") || !strcmp(op, "=") || !strcmp(op, "eq")) { + RETURN_BOOL(r == 0); + } + if (!strcmp(op, "!=") || !strcmp(op, "<>") || !strcmp(op, "ne")) { + RETURN_BOOL(r != 0); + } + + zend_argument_value_error(3, "must be a valid comparison operator"); + RETURN_THROWS(); +} +/* }}} */ + +/* {{{ proto int rpmaddtag(int tag) + add a tag in the default set */ +PHP_FUNCTION(rpmaddtag) +{ + int i; + zend_long tag; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &tag) == FAILURE) { + RETURN_THROWS(); + } + + if (rpmTagGetType(tag) == RPM_NULL_TYPE) { + zend_argument_value_error(1, "Unkown rpmtag"); + RETURN_THROWS(); + } + + if (RPMINFO_G(tags)) { + for (i=0 ; i<RPMINFO_G(nb_tags) ; i++) { + if (RPMINFO_G(tags)[i] == tag) { + RETURN_BOOL(0); + } + } + if (RPMINFO_G(nb_tags) == RPMINFO_G(max_tags)) { + RPMINFO_G(max_tags) += 16; + RPMINFO_G(tags) = erealloc(RPMINFO_G(tags), RPMINFO_G(max_tags) * sizeof(rpmTagVal)); + } + } else { + RPMINFO_G(max_tags) = 16; + RPMINFO_G(tags) = emalloc(RPMINFO_G(max_tags) * sizeof(rpmTagVal)); + } + RPMINFO_G(tags)[RPMINFO_G(nb_tags)++] = tag; + + RETURN_BOOL(1); +} +/* }}} */ + +#ifdef HAVE_ARCHIVE +static ssize_t php_rpm_ops_read(php_stream *stream, char *buf, size_t count) +{ + ssize_t n = -1; + STREAM_DATA_FROM_STREAM(); + + if (self) { + n = rpmfiArchiveRead(self->fi, buf, count); + if (n == 0 || n < (ssize_t)count) { + stream->eof = 1; + } + } + return n; +} + +static void php_rpm_ops_free(struct php_rpm_stream_data_t *self, int close_handle) +{ + if (self) { + if (close_handle) { + Fclose(self->gzdi); + rpmfilesFree(self->files); + rpmfiFree(self->fi); + headerFree(self->h); + } + efree(self); + } +} + +static int php_rpm_ops_close(php_stream *stream, int close_handle) +{ + STREAM_DATA_FROM_STREAM(); + + php_rpm_ops_free(self, close_handle); + stream->abstract = NULL; + + return EOF; +} + +static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb) +{ + STREAM_DATA_FROM_STREAM(); + + if (self) { + struct stat s[2]; /* librpm may use different size (32-bit) */ + int rc; + rc = rpmfiStat(self->fi, 0, s); + memcpy(&ssb->sb, s, sizeof(ssb->sb)); + return rc; + } + return -1; +} + +const php_stream_ops php_stream_rpmio_ops = { + NULL, /* write */ + php_rpm_ops_read, + php_rpm_ops_close, + NULL, /* flush */ + "rpm", + NULL, /* seek */ + NULL, /* cast */ + php_zip_ops_stat, + NULL /* set_option */ +}; + +static struct php_rpm_stream_data_t *php_stream_rpm_finder(const char *path, int want_content) +{ + size_t path_len; + zend_string *file_basename; + char file_dirname[MAXPATHLEN]; + char *fragment; + size_t fragment_len; + struct php_rpm_stream_data_t *self = NULL; + FD_t fdi; + FD_t gzdi; + int rc; + Header h; + char rpmio_flags[80]; + const char *compr; + rpmfiles files; + rpmfi fi; + rpmts ts = rpminfo_getts(); + + fragment = strchr(path, '#'); + if (!fragment) { + return NULL; + } + if (strncasecmp("rpm://", path, 6) == 0) { + path += 6; + } + fragment_len = strlen(fragment); + if (fragment_len < 1) { + return NULL; + } + path_len = strlen(path); + if (path_len >= MAXPATHLEN) { + return NULL; + } + memcpy(file_dirname, path, path_len - fragment_len); + file_dirname[path_len - fragment_len] = '\0'; + file_basename = php_basename(path, path_len - fragment_len, NULL, 0); + fragment++; + if (php_check_open_basedir(file_dirname)) { + zend_string_release_ex(file_basename, 0); + return NULL; + } + fdi = Fopen(file_dirname, "r.ufdio"); + if (Ferror(fdi)) { + zend_string_release_ex(file_basename, 0); + return NULL; + } + rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h); + if (rc != RPMRC_OK && rc != RPMRC_NOKEY && rc != RPMRC_NOTTRUSTED) { + zend_string_release_ex(file_basename, 0); + Fclose(fdi); + return NULL; + } + + compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); + snprintf(rpmio_flags, sizeof(rpmio_flags), "r.%s", compr ? compr : "gzip"); + gzdi = Fdopen(fdi, rpmio_flags); + if (gzdi == NULL) { + headerFree(h); + Fclose(fdi); + zend_string_release_ex(file_basename, 0); + return NULL; + } + + files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); + fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE); + + while((rc = rpmfiNext(fi)) >=0) { + const char *fn = rpmfiFN(fi); + /* + printf("Name=%s, Size=%d, N=%d, mode=%d, reg=%d, content=%d, rdev=%d, inode=%d link=%s\n", fn, + (int)rpmfiFSize(fi), (int)rpmfiFNlink(fi), (int)rpmfiFMode(fi), + (int)S_ISREG(rpmfiFMode(fi)), (int)rpmfiArchiveHasContent(fi), + (int)rpmfiFRdev(fi), (int)rpmfiFInode(fi), rpmfiFLink(fi)); + */ + if (!strcmp(fn, fragment)) { + if (want_content && S_ISREG(rpmfiFMode(fi)) && !rpmfiArchiveHasContent(fi)) { + rpm_rdev_t rdev = rpmfiFRdev(fi); + rpm_ino_t inode = rpmfiFInode(fi); + while((rc = rpmfiNext(fi)) >=0) { + if (rdev == rpmfiFRdev(fi) && inode == rpmfiFInode(fi) && rpmfiArchiveHasContent(fi)) { + break; + } + } + } + break; + } + } + if (rc == RPMERR_ITER_END) { + Fclose(gzdi); + rpmfilesFree(files); + rpmfiFree(fi); + headerFree(h); + } else { + self = emalloc(sizeof(*self)); + self->gzdi = gzdi; + self->files = files; + self->fi = fi; + self->h = h; + } + zend_string_release_ex(file_basename, 0); + + return self; +} + +php_stream *php_stream_rpm_opener(php_stream_wrapper *wrapper, + const char *path, + const char *mode, + int options, + zend_string **opened_path, + php_stream_context *context STREAMS_DC) +{ + struct php_rpm_stream_data_t *self; + + if (mode[0] != 'r') { + return NULL; + } + self = php_stream_rpm_finder(path, 1); + if (self) { + if (opened_path) { + *opened_path = zend_string_init(path, strlen(path), 0); + } + if (!S_ISREG(rpmfiFMode(self->fi)) || !rpmfiArchiveHasContent(self->fi)) { + php_rpm_ops_free(self, 1); + } else { + return php_stream_alloc(&php_stream_rpmio_ops, self, NULL, mode); + } + } + + return NULL; +} + +static int php_stream_rpm_stat(php_stream_wrapper *wrapper, const char *url, int flags, + php_stream_statbuf *ssb, php_stream_context *context) +{ + struct php_rpm_stream_data_t *self; + int rc = -1; + + self = php_stream_rpm_finder(url, 0); + if (self) { + struct stat s[2]; /* librpm may use different size (32-bit) */ + rc = rpmfiStat(self->fi, 0, s); + memcpy(&ssb->sb, s, sizeof(ssb->sb)); + php_rpm_ops_free(self, 1); + } + + return rc; +} + +static const php_stream_wrapper_ops rpm_stream_wops = { + php_stream_rpm_opener, + NULL, /* close */ + NULL, /* fstat */ + php_stream_rpm_stat, + NULL, /* opendir */ + "RPM wrapper", + NULL, /* unlink */ + NULL, /* rename */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL /* metadata */ +}; + +const php_stream_wrapper php_stream_rpm_wrapper = { + &rpm_stream_wops, + NULL, + 0 /* is_url */ +}; + +/* {{{ proto array rpmgetsymlink(string path , string name) + Retrieve soft link target of en entry */ +PHP_FUNCTION(rpmgetsymlink) +{ + char *path, *name; + const char *link; + size_t plen, nlen; + FD_t fdi; + FD_t gzdi; + int rc; + Header h; + char rpmio_flags[80]; + const char *compr; + rpmfiles files; + rpmfi fi; + rpmts ts = rpminfo_getts(); + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "pp", &path, &plen, &name, &nlen) == FAILURE) { + RETURN_THROWS(); + } - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &evr1, &len1, &evr2, &len2) == FAILURE) { - return; + if (php_check_open_basedir(path)) { + RETURN_NULL(); + } + fdi = Fopen(path, "r.ufdio"); + if (Ferror(fdi)) { + RETURN_NULL(); + } + rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h); + if (rc != RPMRC_OK && rc != RPMRC_NOKEY && rc != RPMRC_NOTTRUSTED) { + Fclose(fdi); + RETURN_NULL(); } - RETURN_LONG(rpmvercmp(evr1, evr2)); + compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); + snprintf(rpmio_flags, sizeof(rpmio_flags), "r.%s", compr ? compr : "gzip"); + gzdi = Fdopen(fdi, rpmio_flags); + if (gzdi == NULL) { + headerFree(h); + Fclose(fdi); + RETURN_NULL(); + } + + files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); + fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE); + + rc = rpmfiFindFN(fi, name); + rpmfiSetFX(fi, rc); /* return value have change in 4.18 (from previous to new) */ + if (rc < 0 + || rpmfiFX(fi) != rc + || (link = rpmfiFLink(fi)) == NULL) { + RETVAL_NULL(); + } else { + RETVAL_STRING(link); + } + rpmfiFree(fi); + rpmfilesFree(files); + headerFree(h); + Fclose(gzdi); } /* }}} */ +#endif /* HAVE_ARCHIVE */ + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(rpminfo) { + const char *tagname; + rpmtd names; + REGISTER_STRING_CONSTANT("RPMVERSION", (char *)RPMVERSION, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("RPMSENSE_ANY", RPMSENSE_ANY, CONST_CS | CONST_PERSISTENT); @@ -330,6 +907,22 @@ PHP_MINIT_FUNCTION(rpminfo) REGISTER_LONG_CONSTANT("RPMSENSE_KEYRING", RPMSENSE_KEYRING, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("RPMSENSE_CONFIG", RPMSENSE_CONFIG, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("RPMMIRE_DEFAULT", RPMMIRE_DEFAULT, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("RPMMIRE_STRCMP", RPMMIRE_STRCMP, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("RPMMIRE_REGEX", RPMMIRE_REGEX, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("RPMMIRE_GLOB", RPMMIRE_GLOB, CONST_CS | CONST_PERSISTENT); + + names = rpmtdNew(); + rpmTagGetNames(names, 1); + while ((tagname = rpmtdNextString(names))) { + zend_register_long_constant(tagname, strlen(tagname), rpmTagGetValue(tagname+7), CONST_CS | CONST_PERSISTENT, module_number); + } + rpmtdFree(names); + +#ifdef HAVE_ARCHIVE + php_register_url_stream_wrapper("rpm", &php_stream_rpm_wrapper); +#endif + return SUCCESS; } /* }}} */ @@ -341,6 +934,35 @@ PHP_RINIT_FUNCTION(rpminfo) #if defined(COMPILE_DL_RPMINFO) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif + + RPMINFO_G(nb_tags) = 0; + RPMINFO_G(max_tags) = 0; + RPMINFO_G(tags) = NULL; + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RSHUTDOWN_FUNCTION + */ +PHP_RSHUTDOWN_FUNCTION(rpminfo) +{ + if (RPMINFO_G(ts)) { + if (RPMINFO_G(db)) { + rpmtsCloseDB(RPMINFO_G(ts)); + RPMINFO_G(db) = NULL; + } + rpmtsFree(RPMINFO_G(ts)); + RPMINFO_G(ts) = NULL; + } + + if (RPMINFO_G(tags)) { + efree(RPMINFO_G(tags)); + RPMINFO_G(nb_tags) = 0; + RPMINFO_G(max_tags) = 0; + RPMINFO_G(tags) = NULL; + } + return SUCCESS; } /* }}} */ @@ -352,7 +974,14 @@ PHP_MINFO_FUNCTION(rpminfo) php_info_print_table_start(); php_info_print_table_header(2, "rpminfo support", "enabled"); php_info_print_table_row(2, "Extension version", PHP_RPMINFO_VERSION); + php_info_print_table_row(2, "Author", PHP_RPMINFO_AUTHOR); + php_info_print_table_row(2, "License", PHP_RPMINFO_LICENSE); php_info_print_table_row(2, "RPM library version", RPMVERSION); +#ifdef HAVE_ARCHIVE + php_info_print_table_row(2, "RPM stream wrapper", "yes"); +#else + php_info_print_table_row(2, "RPM stream wrapper", "no"); +#endif php_info_print_table_end(); /* Remove comments if you have entries in php.ini @@ -369,32 +998,10 @@ static PHP_GINIT_FUNCTION(rpminfo) /* {{{ */ ZEND_TSRMLS_CACHE_UPDATE(); #endif rpminfo_globals->ts = NULL; + rpminfo_globals->db = NULL; } /* }}} */ -/* {{{ PHP_GSHUTDOWN_FUNCTION -*/ -PHP_GSHUTDOWN_FUNCTION(rpminfo) -{ - if (rpminfo_globals->ts) { - rpmtsFree(rpminfo_globals->ts); - rpminfo_globals->ts = NULL; - } -} -/* }}} */ - -/* {{{ rpminfo_functions[] - * - * Every user visible function must have an entry in rpminfo_functions[]. - */ -const zend_function_entry rpminfo_functions[] = { - PHP_FE(rpmdbinfo, arginfo_rpmdbinfo) - PHP_FE(rpminfo, arginfo_rpminfo) - PHP_FE(rpmvercmp, arginfo_rpmvercmp) - PHP_FE_END -}; -/* }}} */ - /* {{{ rpminfo_module_entry */ zend_module_entry rpminfo_module_entry = { @@ -402,16 +1009,16 @@ zend_module_entry rpminfo_module_entry = { NULL, NULL, "rpminfo", - rpminfo_functions, + ext_functions, PHP_MINIT(rpminfo), NULL, PHP_RINIT(rpminfo), - NULL, + PHP_RSHUTDOWN(rpminfo), PHP_MINFO(rpminfo), PHP_RPMINFO_VERSION, PHP_MODULE_GLOBALS(rpminfo), PHP_GINIT(rpminfo), - PHP_GSHUTDOWN(rpminfo), + NULL, NULL, STANDARD_MODULE_PROPERTIES_EX }; diff --git a/rpminfo.stub.php b/rpminfo.stub.php new file mode 100644 index 0000000..7e6e32e --- /dev/null +++ b/rpminfo.stub.php @@ -0,0 +1,17 @@ +<?php + +/** @generate-function-entries */ + +function rpmaddtag(int $rpmtag): bool {} + +function rpmdbinfo(string $nevr, bool $full = false): Array|null {} + +function rpmdbsearch(string $pattern, int $rpmtag = RPMTAG_NAME, int $rpmmire = -1, bool $full = false): Array|null {} + +function rpminfo(string $path, bool $full = false, ?string &$error = null): Array|null {} + +function rpmvercmp(string $evr1, string $evr2, ?string $operator = null): int|bool {} + +#ifdef HAVE_ARCHIVE +function rpmgetsymlink(string $path, string $name): string|null {} +#endif diff --git a/rpminfo_arginfo.h b/rpminfo_arginfo.h new file mode 100644 index 0000000..aa0e1d3 --- /dev/null +++ b/rpminfo_arginfo.h @@ -0,0 +1,60 @@ +/* This is a generated file, edit the .stub.php file instead. + * Stub hash: e65e33b4f6ebedcc7ef3030714ebf7e4c06f2778 */ + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmaddtag, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, rpmtag, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmdbinfo, 0, 1, IS_ARRAY, 1) + ZEND_ARG_TYPE_INFO(0, nevr, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, full, _IS_BOOL, 0, "false") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmdbsearch, 0, 1, IS_ARRAY, 1) + ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, rpmtag, IS_LONG, 0, "RPMTAG_NAME") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, rpmmire, IS_LONG, 0, "-1") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, full, _IS_BOOL, 0, "false") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpminfo, 0, 1, IS_ARRAY, 1) + ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, full, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(1, error, IS_STRING, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_rpmvercmp, 0, 2, MAY_BE_LONG|MAY_BE_BOOL) + ZEND_ARG_TYPE_INFO(0, evr1, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, evr2, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, operator, IS_STRING, 1, "null") +ZEND_END_ARG_INFO() + +#if defined(HAVE_ARCHIVE) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmgetsymlink, 0, 2, IS_STRING, 1) + ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) +ZEND_END_ARG_INFO() +#endif + + +ZEND_FUNCTION(rpmaddtag); +ZEND_FUNCTION(rpmdbinfo); +ZEND_FUNCTION(rpmdbsearch); +ZEND_FUNCTION(rpminfo); +ZEND_FUNCTION(rpmvercmp); +#if defined(HAVE_ARCHIVE) +ZEND_FUNCTION(rpmgetsymlink); +#endif + + +static const zend_function_entry ext_functions[] = { + ZEND_FE(rpmaddtag, arginfo_rpmaddtag) + ZEND_FE(rpmdbinfo, arginfo_rpmdbinfo) + ZEND_FE(rpmdbsearch, arginfo_rpmdbsearch) + ZEND_FE(rpminfo, arginfo_rpminfo) + ZEND_FE(rpmvercmp, arginfo_rpmvercmp) +#if defined(HAVE_ARCHIVE) + ZEND_FE(rpmgetsymlink, arginfo_rpmgetsymlink) +#endif + ZEND_FE_END +}; diff --git a/tests/002-rpmvercmp.phpt b/tests/002-rpmvercmp.phpt index 6cffef0..c53a183 100644 --- a/tests/002-rpmvercmp.phpt +++ b/tests/002-rpmvercmp.phpt @@ -3,27 +3,82 @@ Check for rpmvercmp function --SKIPIF-- <?php if (!extension_loaded("rpminfo")) print "skip"; ?> --FILE-- -<?php -var_dump(rpmvercmp("1.0", "1.1")); -var_dump(rpmvercmp("1.1", "1.0")); -var_dump(rpmvercmp("1.0", "1.0")); -// Errors -var_dump(rpmvercmp()); -var_dump(rpmvercmp("a")); -var_dump(rpmvercmp("a", "b", "c")); -?> -Done ---EXPECTF-- -int(-1) -int(1) -int(0) +<?php +$cases = [ + ['1.0', '1.1', -1], + ['1.1', '1.0', 1], + ['1.0', '1.0', 0], + ['1.0', '1', 1], + ['1', '1.1', -1], + ['2.0.14-22.el7_0', '2.0.14.1-35.el7_6', -1], + ['', '', 0], + ['0:1', '1', 0], + ['0:1', '1:1', -1], + ['1:1', '2', 1], + ['1~RC1', '1', -1], + ['1~RC1', '1', -1], + ['1~RC1-1', '1-0', -1], + ['1~beta', '1~RC', 1], + ['1-1', '1-2', -1], + ['1.1-1', '1-1.1', 1], + ['1.1-1~a', '1.1-1', -1], + ['1.2.3-4', '1.2.3p1-2', -1], + ['1.2.3-4', '1.2.3+a-2', -1], +]; +$ok = true; +foreach ($cases as $case) { + list($a,$b,$expected) = $case; + $result = rpmvercmp($a,$b); + if ($result !== $expected) { + $ok = false; + printf("rpmvercmp(%s, %s) = %d when %d expected\n", $a, $b, $result, $expected); + } +} + +$cases = [ + ['1', '2', '>', false], + ['1', '2', 'gt', false], + ['1', '2', '>=', false], + ['1', '2', 'ge', false], + ['1', '1', '>=', true], + ['1', '1', 'ge', true], + + ['1', '2', '<', true], + ['1', '2', 'lt', true], + ['1', '2', '<=', true], + ['1', '2', 'le', true], + ['1', '1', '<=', true], + ['1', '1', 'le', true], -Warning: rpmvercmp() expects exactly 2 parameters, 0 given in %s/002-rpmvercmp.php on line 6 -NULL + ['1', '1', '=', true], + ['1', '1', '==', true], + ['1', '1', 'eq', true], -Warning: rpmvercmp() expects exactly 2 parameters, 1 given in %s/002-rpmvercmp.php on line 7 -NULL + ['1', '2', '=', false], + ['1', '2', '==', false], + ['1', '2', 'eq', false], -Warning: rpmvercmp() expects exactly 2 parameters, 3 given in %s/002-rpmvercmp.php on line 8 -NULL + ['1', '1', '!=', false], + ['1', '1', '<>', false], + ['1', '1', 'ne', false], + + ['1', '2', '!=', true], + ['1', '2', '<>', true], + ['1', '2', 'ne', true], +]; +foreach ($cases as $case) { + list($a,$b,$op,$expected) = $case; + $result = rpmvercmp($a,$b,$op); + if ($result !== $expected) { + $ok = false; + printf("rpmvercmp(%s, %s, %s) = %s when %s expected\n", + $a, $b, $op, $result ? "true" : "false", $expected ? "true" : "false"); + } +} + +if ($ok) echo "OK\n"; +?> +Done +--EXPECTF-- +OK Done diff --git a/tests/003-rpminfo.phpt b/tests/003-rpminfo.phpt index beb7b47..919bcc9 100644 --- a/tests/003-rpminfo.phpt +++ b/tests/003-rpminfo.phpt @@ -14,7 +14,7 @@ array(5) { ["Version"]=> string(1) "1" ["Release"]=> - string(11) "1.fc27.remi" + string(1) "3" ["Summary"]=> string(5) "Bidon" ["Arch"]=> diff --git a/tests/005-rpminfo-full.phpt b/tests/005-rpminfo-full.phpt index 38f5bab..15c158d 100644 --- a/tests/005-rpminfo-full.phpt +++ b/tests/005-rpminfo-full.phpt @@ -24,9 +24,11 @@ Done --- bidon.rpm --- string(5) "bidon" string(15) "A dummy package" -array(1) { +array(2) { [0]=> - string(8) "- create" + string(14) "- add symlinks" + [1]=> + string(20) "- add some hardlinks" } bool(false) array(1) { diff --git a/tests/006-rpminfo-errors.phpt b/tests/006-rpminfo-errors.phpt index edacbdb..5d205d7 100644 --- a/tests/006-rpminfo-errors.phpt +++ b/tests/006-rpminfo-errors.phpt @@ -21,15 +21,15 @@ Done + PHP Warnings Warning: rpminfo(): Can't open '%s/tests/missing.rpm': No such file or directory in %s on line %d -bool(false) +NULL Warning: rpminfo(): Can't read '%s/tests/006-rpminfo-errors.php': Argument is not a RPM file in %s on line %d -bool(false) +NULL + PHP Warnings -bool(false) +NULL string(%d) "Can't open '%s/tests/missing.rpm': No such file or directory" -bool(false) +NULL string(%d) "Can't read '%s/tests/006-rpminfo-errors.php': Argument is not a RPM file" bool(true) NULL diff --git a/tests/007-rpmdbinfo.phpt b/tests/007-rpmdbinfo.phpt index 6fe3116..4a977d1 100644 --- a/tests/007-rpmdbinfo.phpt +++ b/tests/007-rpmdbinfo.phpt @@ -1,15 +1,19 @@ --TEST-- -Check for rpmdbinfo function +Check for rpmdbinfo function on Name --SKIPIF-- <?php if (!extension_loaded("rpminfo")) print "skip"; ?> --FILE-- <?php var_dump(rpmdbinfo('doesntexistsinrpmdb')); var_dump(rpmdbinfo('bash')); +var_dump(rpmaddtag(RPMTAG_INSTALLTIME)); +var_dump(rpmaddtag(RPMTAG_BUILDTIME)); +var_dump(rpmaddtag(RPMTAG_INSTALLTIME)); +var_dump(rpmdbinfo('bash')); ?> Done --EXPECTF-- -bool(false) +NULL array(1) { [0]=> array(5) { @@ -25,4 +29,26 @@ array(1) { string(%d) "%s" } } +bool(true) +bool(true) +bool(false) +array(1) { + [0]=> + array(7) { + ["Name"]=> + string(4) "bash" + ["Version"]=> + string(%d) "%s" + ["Release"]=> + string(%d) "%s" + ["Summary"]=> + string(26) "The GNU Bourne Again shell" + ["Buildtime"]=> + int(%d) + ["Installtime"]=> + int(%d) + ["Arch"]=> + string(%d) "%s" + } +} Done diff --git a/tests/008-rpmdbsearch.phpt b/tests/008-rpmdbsearch.phpt new file mode 100644 index 0000000..f348b92 --- /dev/null +++ b/tests/008-rpmdbsearch.phpt @@ -0,0 +1,67 @@ +--TEST-- +Check for rpmdbinfo function +--SKIPIF-- +<?php if (!extension_loaded("rpminfo")) print "skip"; ?> +--FILE-- +<?php +echo "Name / glob\n"; +$a = rpmdbsearch('php*', RPMTAG_NAME , RPMMIRE_GLOB); +var_dump(count($a) > 1); + +echo "Name / regex\n"; +$a = rpmdbsearch('^php', RPMTAG_NAME, RPMMIRE_REGEX); +var_dump(count($a) > 1); + +echo "Installed file\n"; +$a = rpmdbsearch(PHP_BINARY, RPMTAG_INSTFILENAMES); +var_dump(count($a) == 1); + +$phprpm = $a[0]['Name']; +$p = rpmdbinfo($phprpm, 1); + +echo "Pkgid\n"; +$a = rpmdbsearch($p[0]['Sigmd5'], RPMTAG_PKGID); +var_dump($a[0]['Name'] == $phprpm); + +echo "Hdrid\n"; +$a = rpmdbsearch($p[0]['Sha1header'], RPMTAG_HDRID); +var_dump($a[0]['Name'] == $phprpm); +var_dump(count($a[0]) < 10); + +echo "Hdrid (full)\n"; +$a = rpmdbsearch($p[0]['Sha1header'], RPMTAG_HDRID, -1, true); +var_dump($a[0]['Name'] == $phprpm); +var_dump($a[0]['Sha1header'] == $p[0]['Sha1header']); +var_dump(count($a[0]) > 20); + +echo "Installtid\n"; +$a = rpmdbsearch($p[0]['Installtid'], RPMTAG_INSTALLTID); +var_dump(count($a) >= 1); + +echo "Version\n"; +$a = rpmdbsearch($p[0]['Version'], RPMTAG_VERSION); +var_dump(count($a) > 1); + +?> +Done +--EXPECTF-- +Name / glob +bool(true) +Name / regex +bool(true) +Installed file +bool(true) +Pkgid +bool(true) +Hdrid +bool(true) +bool(true) +Hdrid (full) +bool(true) +bool(true) +bool(true) +Installtid +bool(true) +Version +bool(true) +Done diff --git a/tests/009-rpmdbinfo2.phpt b/tests/009-rpmdbinfo2.phpt new file mode 100644 index 0000000..23f95c5 --- /dev/null +++ b/tests/009-rpmdbinfo2.phpt @@ -0,0 +1,22 @@ +--TEST-- +Check for rpmdbinfo function on NEVR +--SKIPIF-- +<?php +if (!extension_loaded("rpminfo")) print "skip"; +if (!rpmdbinfo('kernel')) print "skip kernel not installed"; +?> +--FILE-- +<?php +$k = rpmdbinfo('kernel'); +var_dump(count($k) > 0); // multiple kernels +$n = $k[0]['Name'] . '-' . $k[0]['Version'] . '-' . $k[0]['Release']; + +$k = rpmdbinfo($n); // single kernel with NEVR +var_dump(count($k) ==1); + +?> +Done +--EXPECTF-- +bool(true) +bool(true) +Done diff --git a/tests/011-rpmvercmp_error8.phpt b/tests/011-rpmvercmp_error8.phpt new file mode 100644 index 0000000..2fe6aa1 --- /dev/null +++ b/tests/011-rpmvercmp_error8.phpt @@ -0,0 +1,37 @@ +--TEST-- +Check for rpmvercmp function +--SKIPIF-- +<?php +if (!extension_loaded("rpminfo")) print "skip"; +if (PHP_VERSION_ID < 80000) print "skip only for PHP 8"; +?> +--FILE-- +<?php +try { + var_dump(rpmvercmp()); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(rpmvercmp("a")); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(rpmvercmp("a", "b", "c")); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(rpmvercmp("a", "b", "c", "d")); +} catch (ArgumentCountError $e) { + echo $e->getMessage(), "\n"; +} +?> +Done +--EXPECTF-- +rpmvercmp() expects at least 2 %s, 0 given +rpmvercmp() expects at least 2 %s, 1 given +rpmvercmp(): Argument #3 ($operator) must be a valid comparison operator +rpmvercmp() expects at most 3 %s, 4 given +Done diff --git a/tests/012-rpmaddtag.phpt b/tests/012-rpmaddtag.phpt new file mode 100644 index 0000000..bf371a4 --- /dev/null +++ b/tests/012-rpmaddtag.phpt @@ -0,0 +1,16 @@ +--TEST-- +Check for rpmaddtag parameter check +--SKIPIF-- +<?php if (!extension_loaded("rpminfo")) print "skip"; ?> +--FILE-- +<?php +var_dump(rpmaddtag(RPMTAG_INSTALLTIME)); +try { + var_dump(rpmaddtag(-1)); +} catch (ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +bool(true) +%A Unkown rpmtag%A diff --git a/tests/013-rpmdbsearch-error.phpt b/tests/013-rpmdbsearch-error.phpt new file mode 100644 index 0000000..4a61227 --- /dev/null +++ b/tests/013-rpmdbsearch-error.phpt @@ -0,0 +1,16 @@ +--TEST-- +Check for rpmdbinfo function +--SKIPIF-- +<?php if (!extension_loaded("rpminfo")) print "skip"; ?> +--FILE-- +<?php +var_dump(rpmdbsearch('notexists', RPMTAG_NAME)); +try { +var_dump(rpmdbsearch('notexists', RPMTAG_NAME, 99)); +} catch (ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +NULL +%A Unkown rpmmire%A diff --git a/tests/014-stream.phpt b/tests/014-stream.phpt new file mode 100644 index 0000000..69b881e --- /dev/null +++ b/tests/014-stream.phpt @@ -0,0 +1,97 @@ +--TEST-- +Check for stream +--SKIPIF-- +<?php +if (!extension_loaded("rpminfo")) print "skip"; +if (version_compare(RPMVERSION, '4.13', 'lt')) print("skip librpm is older than 4.13"); +?> +--FILE-- +<?php +$d = "rpm://" . __DIR__ . "/bidon.rpm#/usr/share/doc/bidon"; +$n = "rpm://" . __DIR__ . "/bidon.rpm#/usr/share/doc/bidon/README"; +$x = "rpm://" . __DIR__ . "/bidon.rpm#/usr/share/doc/bidon/MISSING"; +$foo = "rpm://" . __DIR__ . "/bidon.rpm#/etc/foo.conf"; +$bar = "rpm://" . __DIR__ . "/bidon.rpm#/etc/bar.conf"; +$toto = "rpm://" . __DIR__ . "/bidon.rpm#/etc/toto.conf"; + +echo "+ wrapper\n"; +var_dump(in_array('rpm', stream_get_wrappers())); + +echo "+ stat\n"; +$s = stat($d); // S_ISDIR +var_dump($s['size'], $s['mode'] , ($s['mode'] & 0170000) == 0040000 ? "OK" : "KO"); +var_dump(file_exists($d), is_dir($d), is_file($d), is_link($n)); +$s = stat($n); // S_ISREG +var_dump($s['size'], $s['mode'] , ($s['mode'] & 0170000) == 0100000 ? "OK" : "KO"); +var_dump(file_exists($n), is_dir($n), is_file($n), is_link($n)); +$s = stat($toto); // S_ISLNK +var_dump($s['size'], $s['mode'] , ($s['mode'] & 0170000) == 0120000 ? "OK" : "KO"); +var_dump(file_exists($toto), is_dir($toto), is_file($toto), is_link($toto)); + +echo "+ file\n"; +var_dump($f = fopen($n, "r")); +$s = fstat($f); +var_dump($s['size'], $s['mode']); +var_dump(trim(fread($f, 10))); +var_dump(feof($f)); +var_dump(trim(fread($f, 100))); +var_dump(feof($f)); +fclose($f); + +echo "+ stream\n"; +var_dump(trim(file_get_contents($n))); // Existing file +var_dump(trim(file_get_contents($foo))); // Hardlink with content +var_dump(trim(file_get_contents($bar))); // hardlink without content +var_dump(file_get_contents($x)); // Missing file + +echo "+ symlink\n"; +var_dump(rpmgetsymlink(__DIR__ . "/bidon.rpm", "missing")); +var_dump(rpmgetsymlink(__DIR__ . "/bidon.rpm", "/etc/foo.conf")); // not a symlink +var_dump(rpmgetsymlink(__DIR__ . "/bidon.rpm", "/etc/toto.conf")); // symlink +?> +Done +--EXPECTF-- ++ wrapper +bool(true) ++ stat +int(0) +int(16877) +string(2) "OK" +bool(true) +bool(true) +bool(false) +bool(false) +int(30) +int(33188) +string(2) "OK" +bool(true) +bool(false) +bool(true) +bool(false) +int(8) +int(41471) +string(2) "OK" +bool(true) +bool(false) +bool(false) +bool(true) ++ file +resource(%d) of type (stream) +int(30) +int(33188) +string(10) "Thu Oct 19" +bool(false) +string(18) "12:01:02 CEST 2023" +bool(true) ++ stream +string(29) "Thu Oct 19 12:01:02 CEST 2023" +string(7) "content" +string(7) "content" + +Warning: file_get_contents(%s/bidon.rpm#/usr/share/doc/bidon/MISSING): Failed to open stream: operation failed in %s on line %d +bool(false) ++ symlink +NULL +string(0) "" +string(8) "foo.conf" +Done diff --git a/tests/bidon.rpm b/tests/bidon.rpm Binary files differindex 6cbfa04..d8efb06 100644 --- a/tests/bidon.rpm +++ b/tests/bidon.rpm diff --git a/tests/bidon.spec b/tests/bidon.spec new file mode 100644 index 0000000..b3ad790 --- /dev/null +++ b/tests/bidon.spec @@ -0,0 +1,42 @@ +%{!?ver: %global ver 1} + +Name: bidon +Version: %{ver} +Release: 3 +Summary: Bidon +License: Public Domain +URL: https://rpms.remirepo.net/ + +Obsoletes: fooobs < 2 + + +%description +A dummy package + +%prep +date >README +echo "content" >conf + +%build +: nothing to build + +%install +install -Dpm644 conf %{buildroot}%{_sysconfdir}/foo.conf +cd %{buildroot}%{_sysconfdir} +ln foo.conf bar.conf +ln -s foo.conf toto.conf + +%files +%doc README +%config(noreplace) %{_sysconfdir}/*.conf + + +%changelog +* Thu Oct 19 2023 Remi Collet <remi@fedoraproject.org> - 1-3 +- add symlinks + +* Fri Oct 13 2023 Remi Collet <remi@fedoraproject.org> - 1-2 +- add some hardlinks + +* Wed Dec 24 2014 Remi Collet <remi@fedoraproject.org> - 1-1 +- create |