diff options
Diffstat (limited to 'src/libopkg')
164 files changed, 34213 insertions, 0 deletions
diff --git a/src/libopkg/.svn/all-wcprops b/src/libopkg/.svn/all-wcprops new file mode 100644 index 0000000..9c371fc --- /dev/null +++ b/src/libopkg/.svn/all-wcprops @@ -0,0 +1,491 @@ +K 25 +svn:wc:ra_dav:version-url +V 31 +/svn/!svn/ver/635/trunk/libopkg +END +nv_pair_list.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/552/trunk/libopkg/nv_pair_list.h +END +hash_table.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libopkg/hash_table.h +END +opkg_defines.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/141/trunk/libopkg/opkg_defines.h +END +opkg_pathfinder.c +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/!svn/ver/504/trunk/libopkg/opkg_pathfinder.c +END +opkg_pathfinder.h +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/!svn/ver/279/trunk/libopkg/opkg_pathfinder.h +END +pkg_extract.c +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/558/trunk/libopkg/pkg_extract.c +END +pkg_parse.c +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/620/trunk/libopkg/pkg_parse.c +END +cksum_list.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/612/trunk/libopkg/cksum_list.c +END +pkg_vec.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/553/trunk/libopkg/pkg_vec.c +END +pkg_extract.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/322/trunk/libopkg/pkg_extract.h +END +pkg_parse.h +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/620/trunk/libopkg/pkg_parse.h +END +release.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/613/trunk/libopkg/release.c +END +cksum_list.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/612/trunk/libopkg/cksum_list.h +END +pkg_src_list.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/504/trunk/libopkg/pkg_src_list.c +END +opkg_cmd.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/629/trunk/libopkg/opkg_cmd.c +END +pkg_vec.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/552/trunk/libopkg/pkg_vec.h +END +pkg_hash.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/624/trunk/libopkg/pkg_hash.c +END +md5.c +K 25 +svn:wc:ra_dav:version-url +V 36 +/svn/!svn/ver/53/trunk/libopkg/md5.c +END +release.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/612/trunk/libopkg/release.h +END +opkg_cmd.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/504/trunk/libopkg/opkg_cmd.h +END +pkg_src_list.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/260/trunk/libopkg/pkg_src_list.h +END +pkg_hash.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/616/trunk/libopkg/pkg_hash.h +END +md5.h +K 25 +svn:wc:ra_dav:version-url +V 36 +/svn/!svn/ver/53/trunk/libopkg/md5.h +END +nv_pair.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/504/trunk/libopkg/nv_pair.c +END +sprintf_alloc.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/583/trunk/libopkg/sprintf_alloc.c +END +pkg_dest.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/504/trunk/libopkg/pkg_dest.c +END +nv_pair.h +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/67/trunk/libopkg/nv_pair.h +END +sprintf_alloc.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/581/trunk/libopkg/sprintf_alloc.h +END +pkg_dest.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/595/trunk/libopkg/pkg_dest.h +END +parse_util.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/620/trunk/libopkg/parse_util.c +END +opkg_upgrade.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/552/trunk/libopkg/opkg_upgrade.c +END +parse_util.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/620/trunk/libopkg/parse_util.h +END +opkg_upgrade.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/471/trunk/libopkg/opkg_upgrade.h +END +opkg_remove.c +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/630/trunk/libopkg/opkg_remove.c +END +opkg_utils.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libopkg/opkg_utils.c +END +list.h +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/552/trunk/libopkg/list.h +END +opkg_remove.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/471/trunk/libopkg/opkg_remove.h +END +conffile.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/504/trunk/libopkg/conffile.c +END +opkg_utils.h +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libopkg/opkg_utils.h +END +conffile.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/504/trunk/libopkg/conffile.h +END +pkg_dest_list.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/504/trunk/libopkg/pkg_dest_list.c +END +opkg.c +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/622/trunk/libopkg/opkg.c +END +pkg_dest_list.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/260/trunk/libopkg/pkg_dest_list.h +END +opkg_configure.c +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/504/trunk/libopkg/opkg_configure.c +END +str_list.c +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/552/trunk/libopkg/str_list.c +END +opkg_message.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/582/trunk/libopkg/opkg_message.c +END +opkg_conf.c +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/614/trunk/libopkg/opkg_conf.c +END +opkg.h +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/622/trunk/libopkg/opkg.h +END +opkg_configure.h +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/504/trunk/libopkg/opkg_configure.h +END +str_list.h +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/260/trunk/libopkg/str_list.h +END +sha256.c +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/223/trunk/libopkg/sha256.c +END +opkg_message.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/584/trunk/libopkg/opkg_message.h +END +opkg_conf.h +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/614/trunk/libopkg/opkg_conf.h +END +file_util.c +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/573/trunk/libopkg/file_util.c +END +xsystem.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/504/trunk/libopkg/xsystem.c +END +sha256.h +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/223/trunk/libopkg/sha256.h +END +xsystem.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/552/trunk/libopkg/xsystem.h +END +file_util.h +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/311/trunk/libopkg/file_util.h +END +pkg_depends.c +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/556/trunk/libopkg/pkg_depends.c +END +opkg_download.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/626/trunk/libopkg/opkg_download.c +END +pkg_depends.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/552/trunk/libopkg/pkg_depends.h +END +void_list.c +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/552/trunk/libopkg/void_list.c +END +opkg_download.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/610/trunk/libopkg/opkg_download.h +END +void_list.h +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/260/trunk/libopkg/void_list.h +END +xregex.c +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/552/trunk/libopkg/xregex.c +END +active_list.c +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/552/trunk/libopkg/active_list.c +END +xregex.h +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/33/trunk/libopkg/xregex.h +END +release_parse.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/621/trunk/libopkg/release_parse.c +END +active_list.h +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/552/trunk/libopkg/active_list.h +END +release_parse.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/612/trunk/libopkg/release_parse.h +END +conffile_list.c +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/504/trunk/libopkg/conffile_list.c +END +pkg.c +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/628/trunk/libopkg/pkg.c +END +conffile_list.h +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/260/trunk/libopkg/conffile_list.h +END +opkg_install.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/635/trunk/libopkg/opkg_install.c +END +pkg.h +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/552/trunk/libopkg/pkg.h +END +Makefile.am +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/622/trunk/libopkg/Makefile.am +END +pkg_src.c +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/504/trunk/libopkg/pkg_src.c +END +nv_pair_list.c +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/552/trunk/libopkg/nv_pair_list.c +END +hash_table.c +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/552/trunk/libopkg/hash_table.c +END +opkg_install.h +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/471/trunk/libopkg/opkg_install.h +END +pkg_src.h +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/552/trunk/libopkg/pkg_src.h +END diff --git a/src/libopkg/.svn/entries b/src/libopkg/.svn/entries new file mode 100644 index 0000000..69d71be --- /dev/null +++ b/src/libopkg/.svn/entries @@ -0,0 +1,2782 @@ +10 + +dir +635 +http://opkg.googlecode.com/svn/trunk/libopkg +http://opkg.googlecode.com/svn + + + +2012-01-19T13:52:06.380812Z +635 +pixdamix@gmail.com + + + + + + + + + + + + + + +e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 + +nv_pair_list.h +file + + + + +2012-02-03T08:11:57.067042Z +c55c043adec36fa7d8c58156c0a31266 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1602 + +hash_table.h +file + + + + +2012-02-03T08:11:57.067042Z +9f090a33a18444ca67a7a4eb8659d747 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1569 + +opkg_defines.h +file + + + + +2012-02-03T08:11:57.067042Z +7f5850f46f638764df5e377e3808e355 +2008-12-15T05:26:19.771067Z +141 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +1122 + +opkg_pathfinder.c +file + + + + +2012-02-03T08:11:57.067042Z +2c82910f75bc337f77f5eb008dcefd0e +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2697 + +opkg_pathfinder.h +file + + + + +2012-02-03T08:11:57.067042Z +a914b54879aac75155657e88aa87a097 +2009-11-10T16:29:08.568090Z +279 +pixdamix + + + + + + + + + + + + + + + + + + + + + +884 + +pkg_extract.c +file + + + + +2012-02-03T08:11:57.067042Z +7c5f6039eeefb7defc6c994a62b86a6e +2010-08-24T04:09:34.462297Z +558 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2539 + +pkg_parse.c +file + + + + +2012-02-03T08:11:57.067042Z +865f7e9c705df38eb49b364a9bfd4075 +2011-04-26T13:45:15.094779Z +620 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +7732 + +cksum_list.c +file + + + + +2012-02-03T08:11:57.067042Z +e725dcc5392b3ea1974ebfa3eb6810ed +2011-04-07T15:35:24.424880Z +612 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +2018 + +pkg_vec.c +file + + + + +2012-02-03T08:11:57.067042Z +0b8e31be6285ffe4920876ca1aa8d3f1 +2010-08-18T05:40:17.330024Z +553 +graham.gower + + + + + + + + + + + + + + + + + + + + + +5200 + +pkg_extract.h +file + + + + +2012-02-03T08:11:57.067042Z +7aa6931cf1fa2c0b682915454f9c6f4d +2009-11-17T01:37:24.676869Z +322 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1066 + +pkg_parse.h +file + + + + +2012-02-03T08:11:57.067042Z +70a5056362f6a0ffa3fde5dd1977492f +2011-04-26T13:45:15.094779Z +620 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1737 + +release.c +file + + + + +2012-02-03T08:11:57.067042Z +8eff12e25befa5ac896cb74eb8fb0ec4 +2011-04-07T15:51:52.917110Z +613 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +7881 + +cksum_list.h +file + + + + +2012-02-03T08:11:57.067042Z +8a38b6c2d02f5e055b221f91236d2284 +2011-04-07T15:35:24.424880Z +612 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1237 + +opkg_cmd.c +file + + + + +2012-02-03T08:11:57.067042Z +a6f192a1c2830b1340c2d76ee1024cbd +2011-10-13T03:24:10.549226Z +629 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +35632 + +pkg_vec.h +file + + + + +2012-02-03T08:11:57.067042Z +a25d6bbe828a2b14401b5584ee0f0893 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1898 + +pkg_src_list.c +file + + + + +2012-02-03T08:11:57.067042Z +3930fb054b42b2bf42591528aed77737 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1801 + +pkg_hash.c +file + + + + +2012-02-03T08:11:57.067042Z +f0d7d0e6541a96f3f89d225d011335d4 +2011-07-05T04:23:29.935229Z +624 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +18094 + +md5.c +file + + + + +2012-02-03T08:11:57.067042Z +51a2248c8c83b210b4a69f17a175932c +2008-12-15T05:01:24.764697Z +53 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +14068 + +release.h +file + + + + +2012-02-03T08:11:57.067042Z +2e123481fc7b9c0a029c7c7dcf4a070f +2011-04-07T15:35:24.424880Z +612 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1563 + +opkg_cmd.h +file + + + + +2012-02-03T08:11:57.067042Z +841920b70b5426eee3429fc4924bc63f +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1038 + +pkg_src_list.h +file + + + + +2012-02-03T08:11:57.067042Z +3970dbfec70fbe2a00c6393087733bd0 +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1397 + +pkg_hash.h +file + + + + +2012-02-03T08:11:57.071042Z +f24e2191750aae5144383dd9435bae84 +2011-04-07T16:11:55.055239Z +616 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1928 + +md5.h +file + + + + +2012-02-03T08:11:57.071042Z +0e1f4374aa183b66fe31b6c2146b9fe1 +2008-12-15T05:01:24.764697Z +53 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +4034 + +nv_pair.c +file + + + + +2012-02-03T08:11:57.071042Z +3df039ec552a13676cce6acb9d05ce14 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +979 + +sprintf_alloc.c +file + + + + +2012-02-03T08:11:57.071042Z +d126109b61ebf225aa5a60df49881775 +2010-11-19T04:30:47.443674Z +583 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +1170 + +pkg_dest.c +file + + + + +2012-02-03T08:11:57.071042Z +84362b02a416dd2d2e9f2165bed0c6d6 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2175 + +nv_pair.h +file + + + + +2012-02-03T08:11:57.071042Z +3a4a7b81542f2918357dce3a49857d30 +2008-12-15T05:07:00.671356Z +67 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +864 + +sprintf_alloc.h +file + + + + +2012-02-03T08:11:57.071042Z +50ec93500a043dad1bf71d0319cbe799 +2010-11-19T03:55:52.117655Z +581 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +734 + +pkg_dest.h +file + + + + +2012-02-03T08:11:57.071042Z +4aaf840272e41d65b36abc08949082db +2010-12-23T01:38:40.669296Z +595 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +1026 + +parse_util.c +file + + + + +2012-02-03T08:11:57.071042Z +48ca84baed2d4a32afe79098099c88ec +2011-04-26T13:45:15.094779Z +620 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +3462 + +opkg_upgrade.c +file + + + + +2012-02-03T08:11:57.071042Z +7f62d8700ee1b2e8715c0f8898d96c90 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +3915 + +parse_util.h +file + + + + +2012-02-03T08:11:57.071042Z +694899ad7e4be85c611bc3c6c81a2451 +2011-04-26T13:45:15.094779Z +620 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1084 + +opkg_upgrade.h +file + + + + +2012-02-03T08:11:57.071042Z +8979ba286625349e10f49bb06f5ba11a +2009-12-09T01:20:03.840165Z +471 +graham.gower + + + + + + + + + + + + + + + + + + + + + +768 + +opkg_remove.c +file + + + + +2012-02-03T08:11:57.071042Z +69021e8468eee15d293b0e0bc451467a +2011-10-15T01:12:32.393691Z +630 +google@wwsnet.net + + + + + + + + + + + + + + + + + + + + + +12768 + +opkg_utils.c +file + + + + +2012-02-03T08:11:57.071042Z +68eeed69333a3a2e6d9f76d97f4a32cc +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1824 + +list.h +file + + + + +2012-02-03T08:11:57.071042Z +db2f80ef5dc48b167575aa79bd3aa9a8 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +9507 + +opkg_remove.h +file + + + + +2012-02-03T08:11:57.071042Z +7234ae0ad74f5134be5201ced281016c +2009-12-09T01:20:03.840165Z +471 +graham.gower + + + + + + + + + + + + + + + + + + + + + +925 + +conffile.c +file + + + + +2012-02-03T08:11:57.071042Z +7d24768935686e1e5ce859bbc3761ac7 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1635 + +opkg_utils.h +file + + + + +2012-02-03T08:11:57.071042Z +9002715cbeca19d1a901a5696869961d +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +793 + +conffile.h +file + + + + +2012-02-03T08:11:57.071042Z +4ec8bcbe808326f144652b763bffdc4c +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +902 + +pkg_dest_list.c +file + + + + +2012-02-03T08:11:57.071042Z +7c7bb5df84989b21a8a21406d7954d24 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2075 + +opkg.c +file + + + + +2012-02-03T08:11:57.071042Z +e5383d70147726f0a3b3c59cbc6d8481 +2011-05-26T00:51:50.330823Z +622 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +18331 + +pkg_dest_list.h +file + + + + +2012-02-03T08:11:57.071042Z +dd66a02e1ab85dd4a821595bb41bc21c +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1278 + +opkg_configure.c +file + + + + +2012-02-03T08:11:57.071042Z +1e62e89c3740510ed8e2694a33f1db5a +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1212 + +str_list.c +file + + + + +2012-02-03T08:11:57.071042Z +bc15d70326be50038a70b990a6d86765 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2855 + +opkg_message.c +file + + + + +2012-02-03T08:11:57.071042Z +40f6482e545853cbc4b1e7cd822f1792 +2010-11-19T03:56:06.556794Z +582 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +2532 + +opkg_conf.c +file + + + + +2012-02-03T08:11:57.071042Z +04de03f19438a7b10e0a2889b62fdd88 +2011-04-07T15:53:24.802562Z +614 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +19687 + +opkg.h +file + + + + +2012-02-03T08:11:57.071042Z +d7911b47385dd6363304138c491b4445 +2011-05-26T00:51:50.330823Z +622 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +2076 + +opkg_configure.h +file + + + + +2012-02-03T08:11:57.071042Z +a9bfcd4919274f180fe87a4126dd81d2 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +730 + +str_list.h +file + + + + +2012-02-03T08:11:57.075042Z +ac829c9450bd07c39ccea4ed19023985 +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1551 + +sha256.c +file + + + + +2012-02-03T08:11:57.071042Z +b351bc0fc585795477a2acbca532bb45 +2009-10-28T07:27:13.041060Z +223 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +16811 + +opkg_message.h +file + + + + +2012-02-03T08:11:57.075042Z +fef6779f11e3d287760c44701f67c9c1 +2010-11-19T06:19:11.360886Z +584 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +1450 + +opkg_conf.h +file + + + + +2012-02-03T08:11:57.075042Z +e3d9c298d89225aeb3a4c535903178ff +2011-04-07T15:53:24.802562Z +614 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +3552 + +file_util.c +file + + + + +2012-02-03T08:11:57.075042Z +dce8b7d5d4ebd9bcdb569213acedfa84 +2010-09-21T01:25:04.068092Z +573 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +6318 + +xsystem.c +file + + + + +2012-02-03T08:11:57.075042Z +55e75aa15bce97bbfc7a85367e565148 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1734 + +sha256.h +file + + + + +2012-02-03T08:11:57.075042Z +bc6e05aa74701c3aeaf4f41b61a55e83 +2009-10-28T07:27:13.041060Z +223 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +3492 + +xsystem.h +file + + + + +2012-02-03T08:11:57.075042Z +a27db97a28d27977ddf9312d33565abd +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +994 + +file_util.h +file + + + + +2012-02-03T08:11:57.075042Z +f09d89fc505c040fcfc29022cb5f8fed +2009-11-16T00:13:12.785869Z +311 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1075 + +pkg_depends.c +file + + + + +2012-02-03T08:11:57.075042Z +14d6d6d09b1a76e5078fddee7c3d072a +2010-08-19T01:54:04.588715Z +556 +graham.gower + + + + + + + + + + + + + + + + + + + + + +26019 + +opkg_download.c +file + + + + +2012-02-03T08:11:57.075042Z +a9108e1e45fa49a44b809d0feb3a00bb +2011-09-12T01:24:24.668313Z +626 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +16334 + +pkg_depends.h +file + + + + +2012-02-03T08:11:57.075042Z +b50d4e1912d90b61089f6ec311e9762b +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2481 + +void_list.c +file + + + + +2012-02-03T08:11:57.075042Z +28eeb950b761f0d272b7e6c661b69962 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +4142 + +opkg_download.h +file + + + + +2012-02-03T08:11:57.075042Z +96354835ab92de44a860ad9ea2fe8600 +2011-04-07T15:03:54.460393Z +610 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +1323 + +void_list.h +file + + + + +2012-02-03T08:11:57.075042Z +70c5a66e605144a6acbc84363083893e +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1933 + +xregex.c +file + + + + +2012-02-03T08:11:57.075042Z +0a3463387f1cf216bc5487c20be1a8eb +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1205 + +active_list.c +file + + + + +2012-02-03T08:11:57.075042Z +da09dda5265e65152a15206f4051850c +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +5084 + +xregex.h +file + + + + +2012-02-03T08:11:57.075042Z +eea300b5072555c2f3a02a08fe446408 +2008-12-15T04:25:08.480965Z +33 +ticktock35 + + + + + + + + + + + + + + + + + + + + + +828 + +release_parse.c +file + + + + +2012-02-03T08:11:57.075042Z +cec45dd88b0c4e7bae788f4831e9e880 +2011-04-26T13:48:21.243973Z +621 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +2797 + +active_list.h +file + + + + +2012-02-03T08:11:57.075042Z +6db3ce83f0bf09ab84c59f3298e492b4 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1585 + +release_parse.h +file + + + + +2012-02-03T08:11:57.075042Z +96c623a1ccda282eb1e9a129bf0df8b1 +2011-04-07T15:35:24.424880Z +612 +javiplx@gmail.com + + + + + + + + + + + + + + + + + + + + + +707 + +conffile_list.c +file + + + + +2012-02-03T08:11:57.075042Z +284a111fd513813a93a889d87b7b0388 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1222 + +pkg.c +file + + + + +2012-02-03T08:11:57.075042Z +1daa646ab7dab8118ba7650eb3c6da68 +2011-10-13T03:23:56.362250Z +628 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +35571 + +conffile_list.h +file + + + + +2012-02-03T08:11:57.075042Z +ef0ad4786e956ca0436f2a22392cfb64 +2009-11-05T04:52:10.559388Z +260 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1152 + +opkg_install.c +file + + + + +2012-02-03T08:11:57.075042Z +4fec8ffed0e1b37015c38b4561788ac2 +2012-01-19T13:52:06.380812Z +635 +pixdamix@gmail.com + + + + + + + + + + + + + + + + + + + + + +43767 + +pkg.h +file + + + + +2012-02-03T08:11:57.075042Z +3cf9fd5f5ef5b4447be5eb7f681d515a +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +6950 + +Makefile.am +file + + + + +2012-02-03T08:11:57.075042Z +44f90c09985bdcafb1465b41121ea802 +2011-05-26T00:51:50.330823Z +622 +graham.gower@gmail.com + + + + + + + + + + + + + + + + + + + + + +2151 + +pkg_src.c +file + + + + +2012-02-03T08:11:57.075042Z +88fd559e6dc6cebd52ee45f157fd6f09 +2009-12-21T00:13:22.471616Z +504 +graham.gower + + + + + + + + + + + + + + + + + + + + + +1105 + +nv_pair_list.c +file + + + + +2012-02-03T08:11:57.079042Z +812250e1006486973fe19ee185ae76e5 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +2752 + +hash_table.c +file + + + + +2012-02-03T08:11:57.079042Z +4a4ac8b36aa7c1ed14c16a74fe8cbf41 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +5495 + +opkg_install.h +file + + + + +2012-02-03T08:11:57.079042Z +90e0cc8bb4899be40f537c856ed6f479 +2009-12-09T01:20:03.840165Z +471 +graham.gower + + + + + + + + + + + + + + + + + + + + + +817 + +pkg_src.h +file + + + + +2012-02-03T08:11:57.079042Z +c5e5a41941a1557e33ea209740923260 +2010-08-18T03:39:02.973664Z +552 +graham.gower + + + + + + + + + + + + + + + + + + + + + +918 + diff --git a/src/libopkg/.svn/text-base/Makefile.am.svn-base b/src/libopkg/.svn/text-base/Makefile.am.svn-base new file mode 100644 index 0000000..043c5c4 --- /dev/null +++ b/src/libopkg/.svn/text-base/Makefile.am.svn-base @@ -0,0 +1,55 @@ + +AM_CFLAGS=-Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DOPKGLOCKFILE=\"@opkglockfile@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) $(PATHFINDER_CFLAGS) + +libopkg_includedir=$(includedir)/libopkg +libopkg_include_HEADERS= *.h + + +opkg_libcore_sources = \ + opkg.c opkg.h \ + opkg_defines.h +opkg_cmd_sources = opkg_cmd.c opkg_cmd.h \ + opkg_configure.c opkg_configure.h \ + opkg_download.c opkg_download.h \ + opkg_install.c opkg_install.h \ + opkg_upgrade.c opkg_upgrade.h \ + opkg_remove.c opkg_remove.h +opkg_db_sources = opkg_conf.c opkg_conf.h \ + release.c release.h release_parse.c release_parse.h \ + opkg_utils.c opkg_utils.h pkg.c pkg.h hash_table.h \ + pkg_depends.c pkg_depends.h pkg_extract.c pkg_extract.h \ + hash_table.c pkg_hash.c pkg_hash.h pkg_parse.c pkg_parse.h \ + pkg_vec.c pkg_vec.h +opkg_list_sources = conffile.c conffile.h conffile_list.c conffile_list.h \ + nv_pair.c nv_pair.h nv_pair_list.c nv_pair_list.h \ + pkg_dest.c pkg_dest.h pkg_dest_list.c pkg_dest_list.h \ + pkg_src.c pkg_src.h pkg_src_list.c pkg_src_list.h \ + str_list.c str_list.h void_list.c void_list.h \ + active_list.c active_list.h list.h +opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c md5.c md5.h \ + parse_util.c parse_util.h \ + cksum_list.c cksum_list.h \ + sprintf_alloc.c sprintf_alloc.h \ + xregex.c xregex.h xsystem.c xsystem.h +if HAVE_PATHFINDER +opkg_util_sources += opkg_pathfinder.c opkg_pathfinder.h +endif +if HAVE_SHA256 +opkg_util_sources += sha256.c sha256.h +endif + +lib_LTLIBRARIES = libopkg.la +libopkg_la_SOURCES = \ + $(opkg_libcore_sources) \ + $(opkg_cmd_sources) $(opkg_db_sources) \ + $(opkg_util_sources) $(opkg_list_sources) + +libopkg_la_LIBADD = $(top_builddir)/libbb/libbb.la $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS) + +libopkg_la_LDFLAGS = -version-info 1:0:0 + +# make sure we only export symbols that are for public use +#libopkg_la_LDFLAGS = -export-symbols-regex "^opkg_.*" + + + diff --git a/src/libopkg/.svn/text-base/active_list.c.svn-base b/src/libopkg/.svn/text-base/active_list.c.svn-base new file mode 100644 index 0000000..69ac1d1 --- /dev/null +++ b/src/libopkg/.svn/text-base/active_list.c.svn-base @@ -0,0 +1,165 @@ +/* active_list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko 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, 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. +*/ + + +#include "active_list.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "libbb/libbb.h" + +void active_list_init(struct active_list *ptr) { + INIT_LIST_HEAD(&ptr->node); + INIT_LIST_HEAD(&ptr->depend); + ptr->depended = NULL; +} + +/** + */ +struct active_list * active_list_next(struct active_list *head, struct active_list *ptr) { + struct active_list *next=NULL; + if ( !head ) { + opkg_msg(ERROR, "Internal error: head=%p, ptr=%p\n", head, ptr); + return NULL; + } + if ( !ptr ) + ptr = head; + next = list_entry(ptr->node.next, struct active_list, node); + if ( next == head ) { + return NULL; + } + if ( ptr->depended && &ptr->depended->depend == ptr->node.next ) { + return ptr->depended; + } + while ( next->depend.next != &next->depend ) { + next = list_entry(next->depend.next, struct active_list, node); + } + return next; +} + + +struct active_list * active_list_prev(struct active_list *head, struct active_list *ptr) { + struct active_list *prev=NULL; + if ( !head ) { + opkg_msg(ERROR, "Internal error: head=%p, ptr=%p\n", head, ptr); + return NULL; + } + if ( !ptr ) + ptr = head; + if ( ptr->depend.prev != &ptr->depend ) { + prev = list_entry(ptr->depend.prev, struct active_list, node); + return prev; + } + if ( ptr->depended && ptr->depended != head && &ptr->depended->depend == ptr->node.prev ) { + prev = list_entry(ptr->depended->node.prev, struct active_list, node); + } else + prev = list_entry(ptr->node.prev, struct active_list, node); + if ( prev == head ) + return NULL; + return prev; +} + + +struct active_list *active_list_move_node(struct active_list *old_head, struct active_list *new_head, struct active_list *node) { + struct active_list *prev; + if (!old_head || !new_head || !node) + return NULL; + if (old_head == new_head) + return node; + prev = active_list_prev(old_head, node); + active_list_add(new_head, node); + return prev; +} + +static void list_head_clear (struct list_head *head) { + struct active_list *next; + struct list_head *n, *ptr; + if (!head) + return; + list_for_each_safe(ptr, n , head) { + next = list_entry(ptr, struct active_list, node); + if (next->depend.next != &next->depend) { + list_head_clear(&next->depend); + } + active_list_init(next); + } +} +void active_list_clear(struct active_list *head) { + list_head_clear(&head->node); + if (head->depend.next != &head->depend) { + list_head_clear(&head->depend); + } + active_list_init(head); +} + +void active_list_add_depend(struct active_list *node, struct active_list *depend) { + list_del_init(&depend->node); + list_add_tail(&depend->node, &node->depend); + depend->depended = node; +} + +void active_list_add(struct active_list *head, struct active_list *node) { + list_del_init(&node->node); + list_add_tail(&node->node, &head->node); + node->depended = head; +} + +struct active_list * active_list_head_new(void) { + struct active_list * head = xcalloc(1, sizeof(struct active_list)); + active_list_init(head); + return head; +} + +void active_list_head_delete(struct active_list *head) { + active_list_clear(head); + free(head); +} + +/* + * Using insert sort. + * Note. the list should not be large, or it will be very inefficient. + * + */ +struct active_list * active_list_sort(struct active_list *head, int (*compare)(const void *, const void *)) { + struct active_list tmphead; + struct active_list *node, *ptr; + if ( !head ) + return NULL; + active_list_init(&tmphead); + for (node = active_list_next(head, NULL); node; node = active_list_next(head, NULL)) { + if (tmphead.node.next == &tmphead.node) { + active_list_move_node(head, &tmphead, node); + } else { + for (ptr = active_list_next(&tmphead, NULL); ptr; ptr=active_list_next(&tmphead, ptr)) { + if (compare(ptr, node) <= 0) { + break; + } + } + if (!ptr) { + active_list_move_node(head, &tmphead, node); + } else { + active_list_move_node(head, ptr, node); + } + } + node->depended = &tmphead; + } + for (ptr = active_list_prev(&tmphead, NULL); ptr; ptr=active_list_prev(&tmphead, NULL)) { + active_list_move_node(&tmphead, head, ptr); + } + return head; +} diff --git a/src/libopkg/.svn/text-base/active_list.h.svn-base b/src/libopkg/.svn/text-base/active_list.h.svn-base new file mode 100644 index 0000000..ecb79a6 --- /dev/null +++ b/src/libopkg/.svn/text-base/active_list.h.svn-base @@ -0,0 +1,44 @@ +/* active_list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko 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, 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. +*/ + +#ifndef ACTIVE_LIST_H +#define ACTIVE_LIST_H + +#include "list.h" + +struct active_list { + struct list_head node; + struct list_head depend; + struct active_list *depended; +}; + + +struct active_list * active_list_head_new(void); +void active_list_head_delete(struct active_list *); +void active_list_init(struct active_list *ptr); +void active_list_clear(struct active_list *head); +void active_list_add_depend(struct active_list *node, struct active_list *depend); +void active_list_add(struct active_list *head, struct active_list *node); +struct active_list *active_list_move_node(struct active_list *old_head, struct active_list *new_head, struct active_list *node); + +struct active_list * active_list_sort(struct active_list *head, int (*compare_fcn_t)(const void *, const void *)); + +struct active_list * active_list_next(struct active_list *head, struct active_list *ptr); + +struct active_list * active_list_prev(struct active_list *head, struct active_list *ptr); + +#endif diff --git a/src/libopkg/.svn/text-base/cksum_list.c.svn-base b/src/libopkg/.svn/text-base/cksum_list.c.svn-base new file mode 100644 index 0000000..d17151d --- /dev/null +++ b/src/libopkg/.svn/text-base/cksum_list.c.svn-base @@ -0,0 +1,87 @@ +/* cksum_lis.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> + +#include "cksum_list.h" +#include "libbb/libbb.h" + + +int cksum_init(cksum_t *cksum, char **itemlist) +{ + cksum->value = xstrdup(*itemlist++); + cksum->size = atoi(*itemlist++); + cksum->name = xstrdup(*itemlist++); + + return 0; +} + +void cksum_deinit(cksum_t *cksum) +{ + free (cksum->name); + cksum->name = NULL; + + free (cksum->value); + cksum->value = NULL; +} + +void cksum_list_init(cksum_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void cksum_list_deinit(cksum_list_t *list) +{ + cksum_list_elt_t *iter, *n; + cksum_t *cksum; + + list_for_each_entry_safe(iter, n, &list->head, node) { + cksum = (cksum_t *)iter->data; + cksum_deinit(cksum); + + /* malloced in cksum_list_append */ + free(cksum); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist) +{ + /* freed in cksum_list_deinit */ + cksum_t *cksum = xcalloc(1, sizeof(cksum_t)); + cksum_init(cksum, itemlist); + + void_list_append((void_list_t *) list, cksum); + + return cksum; +} + +const cksum_t *cksum_list_find(cksum_list_t *list, const char *name) +{ + cksum_list_elt_t *iter; + cksum_t *cksum; + + list_for_each_entry(iter, &list->head, node) { + cksum = (cksum_t *)iter->data; + if (strcmp(cksum->name, name) == 0) { + return cksum; + } + } + return NULL; +} + diff --git a/src/libopkg/.svn/text-base/cksum_list.h.svn-base b/src/libopkg/.svn/text-base/cksum_list.h.svn-base new file mode 100644 index 0000000..b752288 --- /dev/null +++ b/src/libopkg/.svn/text-base/cksum_list.h.svn-base @@ -0,0 +1,46 @@ +/* cksum_list.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#ifndef CKSUM_LIST_H +#define CKSUM_LIST_H + +typedef struct +{ + char *name; + char *value; + int size; +} cksum_t; + +int cksum_init(cksum_t *cksum, char **itemlist); +void cksum_deinit(cksum_t *cksum); + +#include "void_list.h" + +typedef struct void_list_elt cksum_list_elt_t; + +typedef struct void_list cksum_list_t; + +static inline int cksum_list_empty(cksum_list_t *list) +{ + return void_list_empty ((void_list_t *)list); +} + +void cksum_list_init(cksum_list_t *list); +void cksum_list_deinit(cksum_list_t *list); + +cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist); +const cksum_t *cksum_list_find(cksum_list_t *list, const char *name); + +#endif diff --git a/src/libopkg/.svn/text-base/conffile.c.svn-base b/src/libopkg/.svn/text-base/conffile.c.svn-base new file mode 100644 index 0000000..bf8b2a5 --- /dev/null +++ b/src/libopkg/.svn/text-base/conffile.c.svn-base @@ -0,0 +1,63 @@ +/* conffile.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "opkg_message.h" +#include "conffile.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "opkg_conf.h" + +int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum) +{ + return nv_pair_init(conffile, file_name, md5sum); +} + +void conffile_deinit(conffile_t *conffile) +{ + nv_pair_deinit(conffile); +} + +int conffile_has_been_modified(conffile_t *conffile) +{ + char *md5sum; + char *filename = conffile->name; + char *root_filename; + int ret = 1; + + if (conffile->value == NULL) { + opkg_msg(NOTICE, "Conffile %s has no md5sum.\n", conffile->name); + return 1; + } + + root_filename = root_filename_alloc(filename); + + md5sum = file_md5sum_alloc(root_filename); + + if (md5sum && (ret = strcmp(md5sum, conffile->value))) { + opkg_msg(INFO, "Conffile %s:\n\told md5=%s\n\tnew md5=%s\n", + conffile->name, md5sum, conffile->value); + } + + free(root_filename); + if (md5sum) + free(md5sum); + + return ret; +} diff --git a/src/libopkg/.svn/text-base/conffile.h.svn-base b/src/libopkg/.svn/text-base/conffile.h.svn-base new file mode 100644 index 0000000..a188c6d --- /dev/null +++ b/src/libopkg/.svn/text-base/conffile.h.svn-base @@ -0,0 +1,29 @@ +/* conffile.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef CONFFILE_H +#define CONFFILE_H + +#include "nv_pair.h" +typedef struct nv_pair conffile_t; + +int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum); +void conffile_deinit(conffile_t *conffile); +int conffile_has_been_modified(conffile_t *conffile); + +#endif + diff --git a/src/libopkg/.svn/text-base/conffile_list.c.svn-base b/src/libopkg/.svn/text-base/conffile_list.c.svn-base new file mode 100644 index 0000000..1db7790 --- /dev/null +++ b/src/libopkg/.svn/text-base/conffile_list.c.svn-base @@ -0,0 +1,46 @@ +/* conffile_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "conffile_list.h" + +void conffile_list_init(conffile_list_t *list) +{ + nv_pair_list_init(list); +} + +void conffile_list_deinit(conffile_list_t *list) +{ + nv_pair_list_deinit(list); +} + +conffile_t *conffile_list_append(conffile_list_t *list, const char *file_name, + const char *md5sum) +{ + return nv_pair_list_append(list, file_name, md5sum); +} + +void conffile_list_push(conffile_list_t *list, conffile_t *data) +{ + nv_pair_list_push(list, data); +} + +conffile_list_elt_t *conffile_list_pop(conffile_list_t *list) +{ + conffile_list_elt_t *pos = nv_pair_list_pop(list); + return pos; +} + diff --git a/src/libopkg/.svn/text-base/conffile_list.h.svn-base b/src/libopkg/.svn/text-base/conffile_list.h.svn-base new file mode 100644 index 0000000..942f68e --- /dev/null +++ b/src/libopkg/.svn/text-base/conffile_list.h.svn-base @@ -0,0 +1,37 @@ +/* conffile_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef CONFFILE_LIST_H +#define CONFFILE_LIST_H + +#include "nv_pair_list.h" + +typedef nv_pair_list_elt_t conffile_list_elt_t; +typedef nv_pair_list_t conffile_list_t; + +#include "conffile.h" + +void conffile_list_init(conffile_list_t *list); +void conffile_list_deinit(conffile_list_t *list); + +conffile_t *conffile_list_append(conffile_list_t *list, const char *name, + const char *root_dir); +void conffile_list_push(conffile_list_t *list, conffile_t *data); +conffile_list_elt_t *conffile_list_pop(conffile_list_t *list); + +#endif + diff --git a/src/libopkg/.svn/text-base/file_util.c.svn-base b/src/libopkg/.svn/text-base/file_util.c.svn-base new file mode 100644 index 0000000..897546e --- /dev/null +++ b/src/libopkg/.svn/text-base/file_util.c.svn-base @@ -0,0 +1,315 @@ +/* file_util.c - convenience routines for common stat operations + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> + +#include "sprintf_alloc.h" +#include "file_util.h" +#include "md5.h" +#include "libbb/libbb.h" + +#if defined HAVE_SHA256 +#include "sha256.h" +#endif + +int +file_exists(const char *file_name) +{ + struct stat st; + + if (stat(file_name, &st) == -1) + return 0; + + return 1; +} + +int +file_is_dir(const char *file_name) +{ + struct stat st; + + if (stat(file_name, &st) == -1) + return 0; + + return S_ISDIR(st.st_mode); +} + +/* read a single line from a file, stopping at a newline or EOF. + If a newline is read, it will appear in the resulting string. + Return value is a malloc'ed char * which should be freed at + some point by the caller. + + Return value is NULL if the file is at EOF when called. +*/ +char * +file_read_line_alloc(FILE *fp) +{ + char buf[BUFSIZ]; + unsigned int buf_len; + char *line = NULL; + unsigned int line_size = 0; + int got_nl = 0; + + buf[0] = '\0'; + + while (fgets(buf, BUFSIZ, fp)) { + buf_len = strlen(buf); + if (buf[buf_len - 1] == '\n') { + buf_len--; + buf[buf_len] = '\0'; + got_nl = 1; + } + if (line) { + line_size += buf_len; + line = xrealloc(line, line_size+1); + strncat(line, buf, line_size); + } else { + line_size = buf_len + 1; + line = xstrdup(buf); + } + if (got_nl) + break; + } + + return line; +} + +int +file_move(const char *src, const char *dest) +{ + int err; + + err = rename(src, dest); + if (err == -1) { + if (errno == EXDEV) { + /* src & dest live on different file systems */ + err = file_copy(src, dest); + if (err == 0) + unlink(src); + } else { + opkg_perror(ERROR, "Failed to rename %s to %s", + src, dest); + } + } + + return err; +} + +int +file_copy(const char *src, const char *dest) +{ + int err; + + err = copy_file(src, dest, FILEUTILS_FORCE | FILEUTILS_PRESERVE_STATUS); + if (err) + opkg_msg(ERROR, "Failed to copy file %s to %s.\n", + src, dest); + + return err; +} + +int +file_mkdir_hier(const char *path, long mode) +{ + return make_directory(path, mode, FILEUTILS_RECUR); +} + +char *file_md5sum_alloc(const char *file_name) +{ + static const int md5sum_bin_len = 16; + static const int md5sum_hex_len = 32; + + static const unsigned char bin2hex[16] = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + + int i, err; + FILE *file; + char *md5sum_hex; + unsigned char md5sum_bin[md5sum_bin_len]; + + md5sum_hex = xcalloc(1, md5sum_hex_len + 1); + + file = fopen(file_name, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open file %s", file_name); + free(md5sum_hex); + return NULL; + } + + err = md5_stream(file, md5sum_bin); + if (err) { + opkg_msg(ERROR, "Could't compute md5sum for %s.\n", file_name); + fclose(file); + free(md5sum_hex); + return NULL; + } + + fclose(file); + + for (i=0; i < md5sum_bin_len; i++) { + md5sum_hex[i*2] = bin2hex[md5sum_bin[i] >> 4]; + md5sum_hex[i*2+1] = bin2hex[md5sum_bin[i] & 0xf]; + } + + md5sum_hex[md5sum_hex_len] = '\0'; + + return md5sum_hex; +} + +#ifdef HAVE_SHA256 +char *file_sha256sum_alloc(const char *file_name) +{ + static const int sha256sum_bin_len = 32; + static const int sha256sum_hex_len = 64; + + static const unsigned char bin2hex[16] = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + + int i, err; + FILE *file; + char *sha256sum_hex; + unsigned char sha256sum_bin[sha256sum_bin_len]; + + sha256sum_hex = xcalloc(1, sha256sum_hex_len + 1); + + file = fopen(file_name, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open file %s", file_name); + free(sha256sum_hex); + return NULL; + } + + err = sha256_stream(file, sha256sum_bin); + if (err) { + opkg_msg(ERROR, "Could't compute sha256sum for %s.\n", file_name); + fclose(file); + free(sha256sum_hex); + return NULL; + } + + fclose(file); + + for (i=0; i < sha256sum_bin_len; i++) { + sha256sum_hex[i*2] = bin2hex[sha256sum_bin[i] >> 4]; + sha256sum_hex[i*2+1] = bin2hex[sha256sum_bin[i] & 0xf]; + } + + sha256sum_hex[sha256sum_hex_len] = '\0'; + + return sha256sum_hex; +} + +#endif + + +int +rm_r(const char *path) +{ + int ret = 0; + DIR *dir; + struct dirent *dent; + + if (path == NULL) { + opkg_perror(ERROR, "Missing directory parameter"); + return -1; + } + + dir = opendir(path); + if (dir == NULL) { + opkg_perror(ERROR, "Failed to open dir %s", path); + return -1; + } + + if (fchdir(dirfd(dir)) == -1) { + opkg_perror(ERROR, "Failed to change to dir %s", path); + closedir(dir); + return -1; + } + + while (1) { + errno = 0; + if ((dent = readdir(dir)) == NULL) { + if (errno) { + opkg_perror(ERROR, "Failed to read dir %s", + path); + ret = -1; + } + break; + } + + if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) + continue; + +#ifdef _BSD_SOURCE + if (dent->d_type == DT_DIR) { + if ((ret = rm_r(dent->d_name)) == -1) + break; + continue; + } else if (dent->d_type == DT_UNKNOWN) +#endif + { + struct stat st; + if ((ret = lstat(dent->d_name, &st)) == -1) { + opkg_perror(ERROR, "Failed to lstat %s", + dent->d_name); + break; + } + if (S_ISDIR(st.st_mode)) { + if ((ret = rm_r(dent->d_name)) == -1) + break; + continue; + } + } + + if ((ret = unlink(dent->d_name)) == -1) { + opkg_perror(ERROR, "Failed to unlink %s", dent->d_name); + break; + } + } + + if (chdir("..") == -1) { + ret = -1; + opkg_perror(ERROR, "Failed to change to dir %s/..", path); + } + + if (rmdir(path) == -1 ) { + ret = -1; + opkg_perror(ERROR, "Failed to remove dir %s", path); + } + + if (closedir(dir) == -1) { + ret = -1; + opkg_perror(ERROR, "Failed to close dir %s", path); + } + + return ret; +} diff --git a/src/libopkg/.svn/text-base/file_util.h.svn-base b/src/libopkg/.svn/text-base/file_util.h.svn-base new file mode 100644 index 0000000..cfad551 --- /dev/null +++ b/src/libopkg/.svn/text-base/file_util.h.svn-base @@ -0,0 +1,31 @@ +/* file_util.h - convenience routines for common file operations + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef FILE_UTIL_H +#define FILE_UTIL_H + +int file_exists(const char *file_name); +int file_is_dir(const char *file_name); +char *file_read_line_alloc(FILE *file); +int file_move(const char *src, const char *dest); +int file_copy(const char *src, const char *dest); +int file_mkdir_hier(const char *path, long mode); +char *file_md5sum_alloc(const char *file_name); +char *file_sha256sum_alloc(const char *file_name); +int rm_r(const char *path); + +#endif diff --git a/src/libopkg/.svn/text-base/hash_table.c.svn-base b/src/libopkg/.svn/text-base/hash_table.c.svn-base new file mode 100644 index 0000000..37b53e9 --- /dev/null +++ b/src/libopkg/.svn/text-base/hash_table.c.svn-base @@ -0,0 +1,215 @@ +/* hash.c - hash tables for opkg + + Steven M. Ayer, Jamey Hicks + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "hash_table.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + + +static unsigned long +djb2_hash(const unsigned char *str) +{ + unsigned long hash = 5381; + int c; + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + return hash; +} + +static int +hash_index(hash_table_t *hash, const char *key) +{ + return djb2_hash((const unsigned char *)key) % hash->n_buckets; +} + +/* + * this is an open table keyed by strings + */ +void +hash_table_init(const char *name, hash_table_t *hash, int len) +{ + if (hash->entries != NULL) { + opkg_msg(ERROR, "Internal error: non empty hash table.\n"); + return; + } + + memset(hash, 0, sizeof(hash_table_t)); + + hash->name = name; + hash->n_buckets = len; + hash->entries = xcalloc(hash->n_buckets, sizeof(hash_entry_t)); +} + +void +hash_print_stats(hash_table_t *hash) +{ + printf("hash_table: %s, %d bytes\n" + "\tn_buckets=%d, n_elements=%d, n_collisions=%d\n" + "\tmax_bucket_len=%d, n_used_buckets=%d, ave_bucket_len=%.2f\n" + "\tn_hits=%d, n_misses=%d\n", + hash->name, + hash->n_buckets*(int)sizeof(hash_entry_t), + hash->n_buckets, + hash->n_elements, + hash->n_collisions, + hash->max_bucket_len, + hash->n_used_buckets, + (hash->n_used_buckets ? + ((float)hash->n_elements)/hash->n_used_buckets : 0.0f), + hash->n_hits, + hash->n_misses); +} + +void hash_table_deinit(hash_table_t *hash) +{ + int i; + if (!hash) + return; + + /* free the reminaing entries */ + for (i = 0; i < hash->n_buckets; i++) { + hash_entry_t *hash_entry = (hash->entries + i); + free (hash_entry->key); + /* skip the first entry as this is part of the array */ + hash_entry = hash_entry->next; + while (hash_entry) + { + hash_entry_t *old = hash_entry; + hash_entry = hash_entry->next; + free (old->key); + free (old); + } + } + + free (hash->entries); + + hash->entries = NULL; + hash->n_buckets = 0; +} + +void *hash_table_get(hash_table_t *hash, const char *key) +{ + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + while (hash_entry) + { + if (hash_entry->key) + { + if (strcmp(key, hash_entry->key) == 0) { + hash->n_hits++; + return hash_entry->data; + } + } + hash_entry = hash_entry->next; + } + hash->n_misses++; + return NULL; +} + +int hash_table_insert(hash_table_t *hash, const char *key, void *value) +{ + int bucket_len = 0; + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + if (hash_entry->key) { + if (strcmp(hash_entry->key, key) == 0) { + /* alread in table, update the value */ + hash_entry->data = value; + return 0; + } else { + /* + * if this is a collision, we have to go to the end of the ll, + * then add a new entry + * before we can hook up the value + */ + while (hash_entry->next) { + hash_entry = hash_entry->next; + if (strcmp(hash_entry->key, key) == 0) { + hash_entry->data = value; + return 0; + } + bucket_len++; + } + hash_entry->next = xcalloc(1, sizeof(hash_entry_t)); + hash_entry = hash_entry->next; + hash_entry->next = NULL; + + hash->n_collisions++; + if (++bucket_len > hash->max_bucket_len) + hash->max_bucket_len = bucket_len; + } + } else + hash->n_used_buckets++; + + hash->n_elements++; + hash_entry->key = xstrdup(key); + hash_entry->data = value; + + return 0; +} + +int hash_table_remove(hash_table_t *hash, const char *key) +{ + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + hash_entry_t *next_entry=NULL, *last_entry=NULL; + while (hash_entry) + { + if (hash_entry->key) + { + if (strcmp(key, hash_entry->key) == 0) { + free(hash_entry->key); + if (last_entry) { + last_entry->next = hash_entry->next; + free(hash_entry); + } else { + next_entry = hash_entry->next; + if (next_entry) { + memmove(hash_entry, next_entry, sizeof(hash_entry_t)); + free(next_entry); + } else { + memset(hash_entry, 0 , sizeof(hash_entry_t)); + } + } + return 1; + } + } + last_entry = hash_entry; + hash_entry = hash_entry->next; + } + return 0; +} + +void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data) +{ + int i; + if (!hash || !f) + return; + + for (i = 0; i < hash->n_buckets; i++) { + hash_entry_t *hash_entry = (hash->entries + i); + do { + if(hash_entry->key) { + f(hash_entry->key, hash_entry->data, data); + } + } while((hash_entry = hash_entry->next)); + } +} + diff --git a/src/libopkg/.svn/text-base/hash_table.h.svn-base b/src/libopkg/.svn/text-base/hash_table.h.svn-base new file mode 100644 index 0000000..472b3e2 --- /dev/null +++ b/src/libopkg/.svn/text-base/hash_table.h.svn-base @@ -0,0 +1,51 @@ +/* hash.h - hash tables for opkg + + Steven M. Ayer, Jamey Hicks + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef _HASH_TABLE_H_ +#define _HASH_TABLE_H_ + +typedef struct hash_entry hash_entry_t; +typedef struct hash_table hash_table_t; + +struct hash_entry { + char * key; + void * data; + struct hash_entry * next; +}; + +struct hash_table { + const char *name; + hash_entry_t * entries; + unsigned int n_buckets; + unsigned int n_elements; + + /* useful stats */ + unsigned int n_used_buckets; + unsigned int n_collisions; + unsigned int max_bucket_len; + unsigned int n_hits, n_misses; +}; + +void hash_table_init(const char *name, hash_table_t *hash, int len); +void hash_table_deinit(hash_table_t *hash); +void hash_print_stats(hash_table_t *hash); +void *hash_table_get(hash_table_t *hash, const char *key); +int hash_table_insert(hash_table_t *hash, const char *key, void *value); +int hash_table_remove(hash_table_t *has, const char *key); +void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data); + +#endif /* _HASH_TABLE_H_ */ diff --git a/src/libopkg/.svn/text-base/list.h.svn-base b/src/libopkg/.svn/text-base/list.h.svn-base new file mode 100644 index 0000000..c1325db --- /dev/null +++ b/src/libopkg/.svn/text-base/list.h.svn-base @@ -0,0 +1,304 @@ +/* list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko 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, 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. + + This is modified from Linux Kernel. +*/ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_POISON1 ((struct list_head *) 0x00100100) +#define LIST_POISON2 ((struct list_head *) 0x00200200) + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +static inline void __list_add(struct list_head *newitem, + struct list_head *prev, + struct list_head *next) { + next->prev = newitem; + newitem->next = next; + newitem->prev = prev; + prev->next = newitem; +} + +/** + * list_add - add a new entry + * @newitem: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *newitem, struct list_head *head) { + __list_add(newitem, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @newitem: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *newitem, struct list_head *head) { + __list_add(newitem, head->prev, head); +} + + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) { + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) { + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) { + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) { + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) { + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) { + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) { + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) { + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) { + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + + + +#define _offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - _offsetof(type,member) );}) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#endif diff --git a/src/libopkg/.svn/text-base/md5.c.svn-base b/src/libopkg/.svn/text-base/md5.c.svn-base new file mode 100644 index 0000000..2213dc1 --- /dev/null +++ b/src/libopkg/.svn/text-base/md5.c.svn-base @@ -0,0 +1,455 @@ +/* Functions to compute MD5 message digest of files or memory blocks. + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995,1996,1997,1999,2000,2001,2005,2006,2008 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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, 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. */ + +/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ + +#include <config.h> + +#include "md5.h" + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef _LIBC +# include <endian.h> +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +/* We need to keep the namespace clean so define the MD5 function + protected using leading __ . */ +# define md5_init_ctx __md5_init_ctx +# define md5_process_block __md5_process_block +# define md5_process_bytes __md5_process_bytes +# define md5_finish_ctx __md5_finish_ctx +# define md5_read_ctx __md5_read_ctx +# define md5_stream __md5_stream +# define md5_buffer __md5_buffer +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (struct md5_ctx *ctx) +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Copy the 4 byte value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void +set_uint32 (char *cp, uint32_t v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. */ +void * +md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) +{ + char *r = resbuf; + set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A)); + set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B)); + set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C)); + set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D)); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +void * +md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) +{ + /* Take yet unprocessed bytes into account. */ + uint32_t bytes = ctx->buflen; + size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + ctx->buffer[size - 2] = SWAP (ctx->total[0] << 3); + ctx->buffer[size - 1] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, size * 4, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (FILE *stream, void *resblock) +{ + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + +process_partial_block: + + /* Process any remaining bytes. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (const char *buffer, size_t len, void *resblock) +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + md5_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + md5_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + uint32_t correct_words[16]; + const uint32_t *words = buffer; + size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t A = ctx->A; + uint32_t B = ctx->B; + uint32_t C = ctx->C; + uint32_t D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + uint32_t *cwp = correct_words; + uint32_t A_save = A; + uint32_t B_save = B; + uint32_t C_save = C; + uint32_t D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + + Here is an equivalent invocation using Perl: + + perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}' + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/src/libopkg/.svn/text-base/md5.h.svn-base b/src/libopkg/.svn/text-base/md5.h.svn-base new file mode 100644 index 0000000..3ae657b --- /dev/null +++ b/src/libopkg/.svn/text-base/md5.h.svn-base @@ -0,0 +1,118 @@ +/* Declaration of functions and data types used for MD5 sum computing + library functions. + Copyright (C) 1995-1997,1999,2000,2001,2004,2005,2006,2008 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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, 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. */ + +#ifndef _MD5_H +#define _MD5_H 1 + +#include <stdio.h> +#include <stdint.h> + +#define MD5_DIGEST_SIZE 16 +#define MD5_BLOCK_SIZE 64 + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#ifndef __THROW +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# else +# define __THROW +# endif +#endif + +#ifndef _LIBC +# define __md5_buffer md5_buffer +# define __md5_finish_ctx md5_finish_ctx +# define __md5_init_ctx md5_init_ctx +# define __md5_process_block md5_process_block +# define __md5_process_bytes md5_process_bytes +# define __md5_read_ctx md5_read_ctx +# define __md5_stream md5_stream +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; + + uint32_t total[2]; + uint32_t buflen; + uint32_t buffer[32]; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW; + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void __md5_process_block (const void *buffer, size_t len, + struct md5_ctx *ctx) __THROW; + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void __md5_process_bytes (const void *buffer, size_t len, + struct md5_ctx *ctx) __THROW; + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW; + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW; + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int __md5_stream (FILE *stream, void *resblock) __THROW; + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *__md5_buffer (const char *buffer, size_t len, + void *resblock) __THROW; + +#endif /* md5.h */ diff --git a/src/libopkg/.svn/text-base/nv_pair.c.svn-base b/src/libopkg/.svn/text-base/nv_pair.c.svn-base new file mode 100644 index 0000000..2728100 --- /dev/null +++ b/src/libopkg/.svn/text-base/nv_pair.c.svn-base @@ -0,0 +1,39 @@ +/* nv_pair.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "nv_pair.h" +#include "libbb/libbb.h" + +int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value) +{ + + nv_pair->name = xstrdup(name); + nv_pair->value = xstrdup(value); + + return 0; +} + +void nv_pair_deinit(nv_pair_t *nv_pair) +{ + free(nv_pair->name); + nv_pair->name = NULL; + + free(nv_pair->value); + nv_pair->value = NULL; +} + + diff --git a/src/libopkg/.svn/text-base/nv_pair.h.svn-base b/src/libopkg/.svn/text-base/nv_pair.h.svn-base new file mode 100644 index 0000000..72513e4 --- /dev/null +++ b/src/libopkg/.svn/text-base/nv_pair.h.svn-base @@ -0,0 +1,32 @@ +/* nv_pair.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef NV_PAIR_H +#define NV_PAIR_H + +typedef struct nv_pair nv_pair_t; +struct nv_pair +{ + char *name; + char *value; +}; + +int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value); +void nv_pair_deinit(nv_pair_t *nv_pair); + +#endif + diff --git a/src/libopkg/.svn/text-base/nv_pair_list.c.svn-base b/src/libopkg/.svn/text-base/nv_pair_list.c.svn-base new file mode 100644 index 0000000..333e721 --- /dev/null +++ b/src/libopkg/.svn/text-base/nv_pair_list.c.svn-base @@ -0,0 +1,98 @@ +/* nv_pair_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "nv_pair.h" +#include "void_list.h" +#include "nv_pair_list.h" +#include "libbb/libbb.h" + +void nv_pair_list_init(nv_pair_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void nv_pair_list_deinit(nv_pair_list_t *list) +{ + nv_pair_list_elt_t *pos; + nv_pair_t *nv_pair; + + while(!void_list_empty(list)) { + pos = nv_pair_list_pop(list); + if (!pos) + break; + nv_pair = (nv_pair_t *) pos->data; + nv_pair_deinit(nv_pair); + /* malloced in nv_pair_list_append */ + free(nv_pair); + pos->data = NULL; + free(pos); + } + void_list_deinit((void_list_t *) list); +} + +nv_pair_t *nv_pair_list_append(nv_pair_list_t *list, const char *name, const char *value) +{ + /* freed in nv_pair_list_deinit */ + nv_pair_t *nv_pair = xcalloc(1, sizeof(nv_pair_t)); + nv_pair_init(nv_pair, name, value); + void_list_append((void_list_t *) list, nv_pair); + + return nv_pair; +} + +void nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list) +{ + return (nv_pair_list_elt_t *) void_list_pop((void_list_t *) list); +} + +char *nv_pair_list_find(nv_pair_list_t *list, char *name) +{ + nv_pair_list_elt_t *iter; + nv_pair_t *nv_pair; + + list_for_each_entry(iter, &list->head, node) { + nv_pair = (nv_pair_t *)iter->data; + if (strcmp(nv_pair->name, name) == 0) { + return nv_pair->value; + } + } + return NULL; +} + +nv_pair_list_elt_t *nv_pair_list_first(nv_pair_list_t *list) { + return (nv_pair_list_elt_t * )void_list_first((void_list_t *) list); +} + +nv_pair_list_elt_t *nv_pair_list_prev(nv_pair_list_t *list, nv_pair_list_elt_t *node) { + return (nv_pair_list_elt_t * )void_list_prev((void_list_t *) list, (void_list_elt_t *)node); +} + +nv_pair_list_elt_t *nv_pair_list_next(nv_pair_list_t *list, nv_pair_list_elt_t *node) { + return (nv_pair_list_elt_t * )void_list_next((void_list_t *) list, (void_list_elt_t *)node); +} + +nv_pair_list_elt_t *nv_pair_list_last(nv_pair_list_t *list) { + return (nv_pair_list_elt_t * )void_list_last((void_list_t *) list); +} + + + diff --git a/src/libopkg/.svn/text-base/nv_pair_list.h.svn-base b/src/libopkg/.svn/text-base/nv_pair_list.h.svn-base new file mode 100644 index 0000000..1223a1f --- /dev/null +++ b/src/libopkg/.svn/text-base/nv_pair_list.h.svn-base @@ -0,0 +1,48 @@ +/* nv_pair_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef NV_PAIR_LIST_H +#define NV_PAIR_LIST_H + +#include "nv_pair.h" +#include "void_list.h" + +typedef struct void_list_elt nv_pair_list_elt_t; + +typedef struct void_list nv_pair_list_t; + +static inline int nv_pair_list_empty(nv_pair_list_t *list) +{ + return void_list_empty ((void_list_t *)list); +} + +void nv_pair_list_init(nv_pair_list_t *list); +void nv_pair_list_deinit(nv_pair_list_t *list); + +nv_pair_t *nv_pair_list_append(nv_pair_list_t *list, + const char *name, const char *value); +void nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data); +nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list); +char *nv_pair_list_find(nv_pair_list_t *list, char *name); + +nv_pair_list_elt_t *nv_pair_list_first(nv_pair_list_t *list); +nv_pair_list_elt_t *nv_pair_list_prev(nv_pair_list_t *list, nv_pair_list_elt_t *node); +nv_pair_list_elt_t *nv_pair_list_next(nv_pair_list_t *list, nv_pair_list_elt_t *node); +nv_pair_list_elt_t *nv_pair_list_last(nv_pair_list_t *list); + +#endif + diff --git a/src/libopkg/.svn/text-base/opkg.c.svn-base b/src/libopkg/.svn/text-base/opkg.c.svn-base new file mode 100644 index 0000000..92f61f4 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg.c.svn-base @@ -0,0 +1,872 @@ +/* opkg.c - the opkg package management system + + Thomas Wood <thomas@openedhand.com> + + Copyright (C) 2008 OpenMoko 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, 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. + */ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <fnmatch.h> + +#include "opkg.h" +#include "opkg_conf.h" + +#include "opkg_install.h" +#include "opkg_configure.h" +#include "opkg_download.h" +#include "opkg_remove.h" +#include "opkg_upgrade.h" + +#include "sprintf_alloc.h" +#include "file_util.h" + +#include <libbb/libbb.h> + +#define opkg_assert(expr) if (!(expr)) { \ + printf ("opkg: file %s: line %d (%s): Assertation '%s' failed",\ + __FILE__, __LINE__, __PRETTY_FUNCTION__, # expr); abort (); } + +#define progress(d, p) d.percentage = p; if (progress_callback) progress_callback (&d, user_data); + +/** Private Functions ***/ + +static int +opkg_configure_packages(char *pkg_name) +{ + pkg_vec_t *all; + int i; + pkg_t *pkg; + int r, err = 0; + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + for (i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + + if (pkg->state_status == SS_UNPACKED) { + r = opkg_configure(pkg); + if (r == 0) { + pkg->state_status = SS_INSTALLED; + pkg->parent->state_status = SS_INSTALLED; + pkg->state_flag &= ~SF_PREFER; + } else { + if (!err) + err = r; + } + } + } + + pkg_vec_free(all); + return err; +} + +struct _curl_cb_data { + opkg_progress_callback_t cb; + opkg_progress_data_t *progress_data; + void *user_data; + int start_range; + int finish_range; +}; + +int +curl_progress_cb(struct _curl_cb_data *cb_data, double t, /* dltotal */ + double d, /* dlnow */ + double ultotal, double ulnow) +{ + int p = (t) ? d * 100 / t : 0; + static int prev = -1; + int progress = 0; + + /* prevent the same value being sent twice (can occur due to rounding) */ + if (p == prev) + return 0; + prev = p; + + if (t < 1) + return 0; + + progress = cb_data->start_range + + (d / t * ((cb_data->finish_range - cb_data->start_range))); + cb_data->progress_data->percentage = progress; + + (cb_data->cb) (cb_data->progress_data, cb_data->user_data); + + return 0; +} + + +static struct opkg_conf saved_conf; +/*** Public API ***/ + +int +opkg_new() +{ + saved_conf = *conf; + + if (opkg_conf_init()) + goto err0; + + if (opkg_conf_load()) + goto err0; + + if (pkg_hash_load_feeds()) + goto err1; + + if (pkg_hash_load_status_files()) + goto err1; + + return 0; + +err1: + pkg_hash_deinit(); +err0: + opkg_conf_deinit(); + return -1; +} + +void +opkg_free(void) +{ +#ifdef HAVE_CURL + opkg_curl_cleanup(); +#endif + opkg_conf_deinit(); +} + +int +opkg_re_read_config_files(void) +{ + opkg_free(); + *conf = saved_conf; + return opkg_new(); +} + +int +opkg_get_option(char *option, void *value) +{ + int i; + extern opkg_option_t options[]; + + opkg_assert(option != NULL); + opkg_assert(value != NULL); + + *(char**)value = NULL; + + for (i=0; options[i].name; i++) { + if (strcmp(options[i].name, option) == 0) + break; + } + + if (options[i].name == NULL) + /* Not found. */ + return -1; + + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + *(int *)value = *(int *)options[i].value; + break; + + case OPKG_OPT_TYPE_INT: + *(int *)value = *(int *)options[i].value; + break; + + case OPKG_OPT_TYPE_STRING: + *(char **)value = xstrdup(*(char **)options[i].value); + break; + } + + return 0; +} + +void +opkg_set_option(char *option, void *value) +{ + int i; + extern opkg_option_t options[]; + + opkg_assert(option != NULL); + opkg_assert(value != NULL); + + for (i=0; options[i].name; i++) { + if (strcmp(options[i].name, option) == 0) + break; + } + + if (options[i].name == NULL) { + opkg_msg(ERROR, "Invalid option: %s\n", option); + return; + } + + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + if ((long)value == 0) + *((int *) options[i].value) = 0; + else + *((int *) options[i].value) = 1; + break; + + case OPKG_OPT_TYPE_INT: + *((int *) options[i].value) = (long)value; + break; + + case OPKG_OPT_TYPE_STRING: + *((char **) options[i].value) = xstrdup((char *)value); + break; + } + +} + +/** + * @brief libopkg API: Install package + * @param package_name The name of package in which is going to install + * @param progress_callback The callback function that report the status to caller. + */ +int +opkg_install_package(const char *package_name, + opkg_progress_callback_t progress_callback, + void *user_data) +{ + int err; + char *stripped_filename; + opkg_progress_data_t pdata; + pkg_t *old, *new; + pkg_vec_t *deps, *all; + int i, ndepends; + char **unresolved = NULL; + + opkg_assert(package_name != NULL); + + /* ... */ + pkg_info_preinstall_check(); + + + /* check to ensure package is not already installed */ + old = pkg_hash_fetch_installed_by_name(package_name); + if (old) { + opkg_msg(ERROR, "Package %s is already installed\n", + package_name); + return -1; + } + + new = pkg_hash_fetch_best_installation_candidate_by_name(package_name); + if (!new) { + opkg_msg(ERROR, "Couldn't find package %s\n", package_name); + return -1; + } + + new->state_flag |= SF_USER; + + pdata.action = -1; + pdata.pkg = new; + + progress(pdata, 0); + + /* find dependancies and download them */ + deps = pkg_vec_alloc(); + /* this function does not return the original package, so we insert it later */ + ndepends = pkg_hash_fetch_unsatisfied_dependencies(new, deps, + &unresolved); + if (unresolved) { + char **tmp = unresolved; + opkg_msg(ERROR, "Couldn't satisfy the following dependencies" + " for %s:\n", package_name); + while (*tmp) { + opkg_msg(ERROR, "\t%s", *tmp); + free(*tmp); + tmp++; + } + free(unresolved); + pkg_vec_free(deps); + opkg_message(ERROR, "\n"); + return -1; + } + + /* insert the package we are installing so that we download it */ + pkg_vec_insert(deps, new); + + /* download package and dependencies */ + for (i = 0; i < deps->len; i++) { + pkg_t *pkg; + struct _curl_cb_data cb_data; + char *url; + + pkg = deps->pkgs[i]; + if (pkg->local_filename) + continue; + + pdata.pkg = pkg; + pdata.action = OPKG_DOWNLOAD; + + if (pkg->src == NULL) { + opkg_msg(ERROR, "Package %s not available from any " + "configured src\n", package_name); + return -1; + } + + sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename); + + /* Get the filename part, without any directory */ + stripped_filename = strrchr(pkg->filename, '/'); + if (!stripped_filename) + stripped_filename = pkg->filename; + + sprintf_alloc(&pkg->local_filename, "%s/%s", conf->tmp_dir, + stripped_filename); + + cb_data.cb = progress_callback; + cb_data.progress_data = &pdata; + cb_data.user_data = user_data; + /* 75% of "install" progress is for downloading */ + cb_data.start_range = 75 * i / deps->len; + cb_data.finish_range = 75 * (i + 1) / deps->len; + + err = opkg_download(url, pkg->local_filename, + (curl_progress_func) curl_progress_cb, + &cb_data, 0); + free(url); + + if (err) { + pkg_vec_free(deps); + return -1; + } + + } + pkg_vec_free(deps); + + /* clear depenacy checked marks, left by pkg_hash_fetch_unsatisfied_dependencies */ + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + for (i = 0; i < all->len; i++) { + all->pkgs[i]->parent->dependencies_checked = 0; + } + pkg_vec_free(all); + + + /* 75% of "install" progress is for downloading */ + pdata.pkg = new; + pdata.action = OPKG_INSTALL; + progress(pdata, 75); + + /* unpack the package */ + err = opkg_install_pkg(new, 0); + + if (err) { + return -1; + } + + progress(pdata, 75); + + /* run configure scripts, etc. */ + err = opkg_configure_packages(NULL); + if (err) { + return -1; + } + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + progress(pdata, 100); + return 0; +} + +int +opkg_remove_package(const char *package_name, + opkg_progress_callback_t progress_callback, void *user_data) +{ + int err; + pkg_t *pkg = NULL; + pkg_t *pkg_to_remove; + opkg_progress_data_t pdata; + + opkg_assert(package_name != NULL); + + pkg_info_preinstall_check(); + + pkg = pkg_hash_fetch_installed_by_name(package_name); + + if (pkg == NULL || pkg->state_status == SS_NOT_INSTALLED) { + opkg_msg(ERROR, "Package %s not installed\n", package_name); + return -1; + } + + pdata.action = OPKG_REMOVE; + pdata.pkg = pkg; + progress(pdata, 0); + + if (conf->restrict_to_default_dest) { + pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(pkg->name, + conf->default_dest); + } else { + pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name); + } + + + progress(pdata, 75); + + err = opkg_remove_pkg(pkg_to_remove, 0); + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + + progress(pdata, 100); + return (err) ? -1 : 0; +} + +int +opkg_upgrade_package(const char *package_name, + opkg_progress_callback_t progress_callback, + void *user_data) +{ + int err; + pkg_t *pkg; + opkg_progress_data_t pdata; + + opkg_assert(package_name != NULL); + + pkg_info_preinstall_check(); + + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(package_name, + conf->default_dest); + } else { + pkg = pkg_hash_fetch_installed_by_name(package_name); + } + + if (!pkg) { + opkg_msg(ERROR, "Package %s not installed\n", package_name); + return -1; + } + + pdata.action = OPKG_INSTALL; + pdata.pkg = pkg; + progress(pdata, 0); + + err = opkg_upgrade_pkg(pkg); + if (err) { + return -1; + } + progress(pdata, 75); + + err = opkg_configure_packages(NULL); + if (err) { + return -1; + } + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + progress(pdata, 100); + return 0; +} + +int +opkg_upgrade_all(opkg_progress_callback_t progress_callback, void *user_data) +{ + pkg_vec_t *installed; + int err = 0; + int i; + pkg_t *pkg; + opkg_progress_data_t pdata; + + pdata.action = OPKG_INSTALL; + pdata.pkg = NULL; + + progress(pdata, 0); + + installed = pkg_vec_alloc(); + pkg_info_preinstall_check(); + + pkg_hash_fetch_all_installed(installed); + for (i = 0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + + pdata.pkg = pkg; + progress(pdata, 99 * i / installed->len); + + err += opkg_upgrade_pkg(pkg); + } + pkg_vec_free(installed); + + if (err) + return 1; + + err = opkg_configure_packages(NULL); + if (err) + return 1; + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + pdata.pkg = NULL; + progress(pdata, 100); + return 0; +} + +int +opkg_update_package_lists(opkg_progress_callback_t progress_callback, + void *user_data) +{ + char *tmp; + int err, result = 0; + char *lists_dir; + pkg_src_list_elt_t *iter; + pkg_src_t *src; + int sources_list_count, sources_done; + opkg_progress_data_t pdata; + + pdata.action = OPKG_DOWNLOAD; + pdata.pkg = NULL; + progress(pdata, 0); + + sprintf_alloc(&lists_dir, "%s", (conf->restrict_to_default_dest) + ? conf->default_dest->lists_dir : conf->lists_dir); + + if (!file_is_dir(lists_dir)) { + if (file_exists(lists_dir)) { + opkg_msg(ERROR, "%s is not a directory\n", lists_dir); + free(lists_dir); + return 1; + } + + err = file_mkdir_hier(lists_dir, 0755); + if (err) { + opkg_msg(ERROR, "Couldn't create lists_dir %s\n", + lists_dir); + free(lists_dir); + return 1; + } + } + + sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir); + if (mkdtemp(tmp) == NULL) { + opkg_perror(ERROR, "Coundn't create temporary directory %s", + tmp); + free(lists_dir); + free(tmp); + return 1; + } + + /* count the number of sources so we can give some progress updates */ + sources_list_count = 0; + sources_done = 0; + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + sources_list_count++; + } + + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + char *url, *list_file_name = NULL; + + src = (pkg_src_t *) iter->data; + + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, + src->extra_data, + src->gzip ? "Packages.gz" : "Packages"); + else + sprintf_alloc(&url, "%s/%s", src->value, + src->gzip ? "Packages.gz" : "Packages"); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + if (src->gzip) { + FILE *in, *out; + struct _curl_cb_data cb_data; + char *tmp_file_name = NULL; + + sprintf_alloc(&tmp_file_name, "%s/%s.gz", tmp, + src->name); + + opkg_msg(INFO, "Downloading %s to %s...\n", url, + tmp_file_name); + + cb_data.cb = progress_callback; + cb_data.progress_data = &pdata; + cb_data.user_data = user_data; + cb_data.start_range = + 100 * sources_done / sources_list_count; + cb_data.finish_range = + 100 * (sources_done + 1) / sources_list_count; + + err = opkg_download(url, tmp_file_name, + (curl_progress_func) curl_progress_cb, + &cb_data, 0); + + if (err == 0) { + opkg_msg(INFO, "Inflating %s...\n", + tmp_file_name); + in = fopen(tmp_file_name, "r"); + out = fopen(list_file_name, "w"); + if (in && out) + unzip(in, out); + else + err = 1; + if (in) + fclose(in); + if (out) + fclose(out); + unlink(tmp_file_name); + } + free(tmp_file_name); + } else + err = opkg_download(url, list_file_name, NULL, NULL, 0); + + if (err) { + opkg_msg(ERROR, "Couldn't retrieve %s\n", url); + result = -1; + } + free(url); + +#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + if (conf->check_signature) { + char *sig_file_name; + /* download detached signitures to verify the package lists */ + /* get the url for the sig file */ + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, + src->extra_data, "Packages.sig"); + else + sprintf_alloc(&url, "%s/%s", src->value, + "Packages.sig"); + + /* create filename for signature */ + sprintf_alloc(&sig_file_name, "%s/%s.sig", lists_dir, + src->name); + + /* make sure there is no existing signature file */ + unlink(sig_file_name); + + err = opkg_download(url, sig_file_name, NULL, NULL, 0); + if (err) { + opkg_msg(ERROR, "Couldn't retrieve %s\n", url); + } else { + int err; + err = opkg_verify_file(list_file_name, + sig_file_name); + if (err == 0) { + opkg_msg(INFO, "Signature check " + "passed for %s", + list_file_name); + } else { + opkg_msg(ERROR, "Signature check " + "failed for %s", + list_file_name); + } + } + free(sig_file_name); + free(url); + } +#else + opkg_msg(INFO, "Signature check skipped for %s as GPG support" + " has not been enabled in this build\n", + list_file_name); +#endif + free(list_file_name); + + sources_done++; + progress(pdata, 100 * sources_done / sources_list_count); + } + + rmdir(tmp); + free(tmp); + free(lists_dir); + + /* Now re-read the package lists to update package hash tables. */ + opkg_re_read_config_files(); + + return result; +} + +static int +pkg_compare_names_and_version(const void *a0, const void *b0) +{ + const pkg_t *a = *(const pkg_t **)a0; + const pkg_t *b = *(const pkg_t **)b0; + int ret; + + ret = strcmp(a->name, b->name); + + if (ret == 0) + ret = pkg_compare_versions(a, b); + + return ret; +} + +int +opkg_list_packages(opkg_package_callback_t callback, void *user_data) +{ + pkg_vec_t *all; + int i; + + opkg_assert(callback); + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + pkg_vec_sort(all, pkg_compare_names_and_version); + + for (i = 0; i < all->len; i++) { + pkg_t *pkg; + + pkg = all->pkgs[i]; + + callback(pkg, user_data); + } + + pkg_vec_free(all); + + return 0; +} + +int +opkg_list_upgradable_packages(opkg_package_callback_t callback, void *user_data) +{ + struct active_list *head; + struct active_list *node; + pkg_t *old = NULL, *new = NULL; + + opkg_assert(callback); + + /* ensure all data is valid */ + pkg_info_preinstall_check(); + + head = prepare_upgrade_list(); + for (node = active_list_next(head, head); node; + node = active_list_next(head, node)) { + old = list_entry(node, pkg_t, list); + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + if (new == NULL) + continue; + callback(new, user_data); + } + active_list_head_delete(head); + return 0; +} + +pkg_t * +opkg_find_package(const char *name, const char *ver, const char *arch, + const char *repo) +{ + int pkg_found = 0; + pkg_t *pkg = NULL; + pkg_vec_t *all; + int i; +#define sstrcmp(x,y) (x && y) ? strcmp (x, y) : 0 + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + for (i = 0; i < all->len; i++) { + char *pkgv; + + pkg = all->pkgs[i]; + + /* check name */ + if (sstrcmp(pkg->name, name)) + continue; + + /* check version */ + pkgv = pkg_version_str_alloc(pkg); + if (sstrcmp(pkgv, ver)) { + free(pkgv); + continue; + } + free(pkgv); + + /* check architecture */ + if (arch) { + if (sstrcmp(pkg->architecture, arch)) + continue; + } + + /* check repository */ + if (repo) { + if (sstrcmp(pkg->src->name, repo)) + continue; + } + + /* match found */ + pkg_found = 1; + break; + } + + pkg_vec_free(all); + + return pkg_found ? pkg : NULL; +} + +/** + * @brief Check the accessibility of repositories. + * @return return how many repositories cannot access. 0 means all okay. + */ +int +opkg_repository_accessibility_check(void) +{ + pkg_src_list_elt_t *iter; + str_list_elt_t *iter1; + str_list_t *src; + int repositories = 0; + int ret = 0; + char *repo_ptr; + char *stmp; + char *host, *end; + + src = str_list_alloc(); + + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + host = strstr(((pkg_src_t *)iter->data)->value, "://") + 3; + end = index(host, '/'); + if (strstr(((pkg_src_t *) iter->data)->value, "://") && end) + stmp = xstrndup(((pkg_src_t *) iter->data)->value, + end - ((pkg_src_t *) iter->data)->value); + else + stmp = xstrdup(((pkg_src_t *) iter->data)->value); + + for (iter1 = str_list_first(src); iter1; + iter1 = str_list_next(src, iter1)) { + if (strstr(iter1->data, stmp)) + break; + } + if (iter1) + continue; + + sprintf_alloc(&repo_ptr, "%s/index.html", stmp); + free(stmp); + + str_list_append(src, repo_ptr); + free(repo_ptr); + repositories++; + } + + while (repositories > 0) { + iter1 = str_list_pop(src); + repositories--; + + if (opkg_download(iter1->data, "/dev/null", NULL, NULL, 0)) + ret++; + str_list_elt_deinit(iter1); + } + + free(src); + + return ret; +} diff --git a/src/libopkg/.svn/text-base/opkg.h.svn-base b/src/libopkg/.svn/text-base/opkg.h.svn-base new file mode 100644 index 0000000..4fbd404 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg.h.svn-base @@ -0,0 +1,61 @@ +/* opkg.h - the opkg package management system + + Thomas Wood <thomas@openedhand.com> + + Copyright (C) 2008 OpenMoko 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, 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. +*/ + +#ifndef OPKG_H +#define OPKG_H + +#include "pkg.h" +#include "opkg_message.h" + +typedef struct _opkg_progress_data_t opkg_progress_data_t; + +typedef void (*opkg_progress_callback_t) (const opkg_progress_data_t *progress, void *user_data); +typedef void (*opkg_package_callback_t) (pkg_t *pkg, void *user_data); + +enum _opkg_action_t +{ + OPKG_INSTALL, + OPKG_REMOVE, + OPKG_DOWNLOAD +}; + +struct _opkg_progress_data_t +{ + int percentage; + int action; + pkg_t *pkg; +}; + +int opkg_new (void); +void opkg_free (void); +int opkg_re_read_config_files (void); +int opkg_get_option (char *option, void *value); +void opkg_set_option (char *option, void *value); + +int opkg_install_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_remove_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_upgrade_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_upgrade_all (opkg_progress_callback_t callback, void *user_data); +int opkg_update_package_lists (opkg_progress_callback_t callback, void *user_data); + +int opkg_list_packages (opkg_package_callback_t callback, void *user_data); +int opkg_list_upgradable_packages (opkg_package_callback_t callback, void *user_data); +pkg_t* opkg_find_package (const char *name, const char *version, const char *architecture, const char *repository); + +int opkg_repository_accessibility_check(void); + +#endif /* OPKG_H */ diff --git a/src/libopkg/.svn/text-base/opkg_cmd.c.svn-base b/src/libopkg/.svn/text-base/opkg_cmd.c.svn-base new file mode 100644 index 0000000..11e7867 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_cmd.c.svn-base @@ -0,0 +1,1319 @@ +/* opkg_cmd.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <dirent.h> +#include <glob.h> +#include <fnmatch.h> +#include <signal.h> +#include <unistd.h> + +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "opkg_message.h" +#include "release.h" +#include "pkg.h" +#include "pkg_dest.h" +#include "pkg_parse.h" +#include "sprintf_alloc.h" +#include "pkg.h" +#include "file_util.h" +#include "libbb/libbb.h" +#include "opkg_utils.h" +#include "opkg_defines.h" +#include "opkg_download.h" +#include "opkg_install.h" +#include "opkg_upgrade.h" +#include "opkg_remove.h" +#include "opkg_configure.h" +#include "xsystem.h" + +static void +print_pkg(pkg_t *pkg) +{ + char *version = pkg_version_str_alloc(pkg); + if (pkg->description) + printf("%s - %s - %s\n", pkg->name, version, pkg->description); + else + printf("%s - %s\n", pkg->name, version); + free(version); +} + +int opkg_state_changed; + +static void +write_status_files_if_changed(void) +{ + if (opkg_state_changed && !conf->noaction) { + opkg_msg(INFO, "Writing status file.\n"); + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + sync(); + } else { + opkg_msg(DEBUG, "Nothing to be done.\n"); + } +} + +static void +sigint_handler(int sig) +{ + signal(sig, SIG_DFL); + opkg_msg(NOTICE, "Interrupted. Writing out status database.\n"); + write_status_files_if_changed(); + exit(128 + sig); +} + +static int +opkg_update_cmd(int argc, char **argv) +{ + char *tmp; + int err; + int failures; + char *lists_dir; + pkg_src_list_elt_t *iter; + pkg_src_t *src; + + + sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir); + + if (! file_is_dir(lists_dir)) { + if (file_exists(lists_dir)) { + opkg_msg(ERROR, "%s exists, but is not a directory.\n", + lists_dir); + free(lists_dir); + return -1; + } + err = file_mkdir_hier(lists_dir, 0755); + if (err) { + free(lists_dir); + return -1; + } + } + + failures = 0; + + sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir); + if (mkdtemp (tmp) == NULL) { + opkg_perror(ERROR, "Failed to make temp dir %s", conf->tmp_dir); + return -1; + } + + + for (iter = void_list_first(&conf->dist_src_list); iter; iter = void_list_next(&conf->dist_src_list, iter)) { + char *url, *list_file_name; + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&url, "%s/dists/%s/Release", src->value, src->name); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + err = opkg_download(url, list_file_name, NULL, NULL, 0); + if (!err) { + opkg_msg(NOTICE, "Downloaded release files for dist %s.\n", + src->name); + release_t *release = release_new(); + err = release_init_from_file(release, list_file_name); + if (!err) { + if (!release_comps_supported(release, src->extra_data)) + err = -1; + } + if (!err) { + err = release_download(release, src, lists_dir, tmp); + } + release_deinit(release); + if (err) + unlink(list_file_name); + } + + if (err) + failures++; + + free(list_file_name); + free(url); + } + + for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) { + char *url, *list_file_name; + + src = (pkg_src_t *)iter->data; + + if (src->extra_data && !strcmp(src->extra_data, "__dummy__ ")) + continue; + + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, + src->gzip ? "Packages.gz" : "Packages"); + else + sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages"); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + if (src->gzip) { + char *tmp_file_name; + FILE *in, *out; + + sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name); + err = opkg_download(url, tmp_file_name, NULL, NULL, 0); + if (err == 0) { + opkg_msg(NOTICE, "Inflating %s.\n", url); + in = fopen (tmp_file_name, "r"); + out = fopen (list_file_name, "w"); + if (in && out) + unzip (in, out); + else + err = 1; + if (in) + fclose (in); + if (out) + fclose (out); + unlink (tmp_file_name); + } + free(tmp_file_name); + } else + err = opkg_download(url, list_file_name, NULL, NULL, 0); + if (err) { + failures++; + } else { + opkg_msg(NOTICE, "Updated list of available packages in %s.\n", + list_file_name); + } + free(url); +#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + if (conf->check_signature) { + /* download detached signitures to verify the package lists */ + /* get the url for the sig file */ + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, + "Packages.sig"); + else + sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig"); + + /* create temporary file for it */ + char *tmp_file_name; + + /* Put the signature in the right place */ + sprintf_alloc (&tmp_file_name, "%s/%s.sig", lists_dir, src->name); + + err = opkg_download(url, tmp_file_name, NULL, NULL, 0); + if (err) { + failures++; + opkg_msg(NOTICE, "Signature check failed.\n"); + } else { + err = opkg_verify_file (list_file_name, tmp_file_name); + if (err == 0) + opkg_msg(NOTICE, "Signature check passed.\n"); + else + opkg_msg(NOTICE, "Signature check failed.\n"); + } + if (err) { + /* The signature was wrong so delete it */ + opkg_msg(NOTICE, "Remove wrong Signature file.\n"); + unlink (tmp_file_name); + unlink (list_file_name); + } + /* We shouldn't unlink the signature ! */ + // unlink (tmp_file_name); + free (tmp_file_name); + free (url); + } +#else + // Do nothing +#endif + free(list_file_name); + } + rmdir (tmp); + free (tmp); + free(lists_dir); + + return failures; +} + + +struct opkg_intercept +{ + char *oldpath; + char *statedir; +}; + +typedef struct opkg_intercept *opkg_intercept_t; + +static opkg_intercept_t +opkg_prep_intercepts(void) +{ + opkg_intercept_t ctx; + char *newpath; + + ctx = xcalloc(1, sizeof (*ctx)); + ctx->oldpath = xstrdup(getenv("PATH")); + sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath); + sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX", conf->tmp_dir); + + if (mkdtemp(ctx->statedir) == NULL) { + opkg_perror(ERROR,"Failed to make temp dir %s", ctx->statedir); + free(ctx->oldpath); + free(ctx->statedir); + free(newpath); + free(ctx); + return NULL; + } + + setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1); + setenv("PATH", newpath, 1); + free(newpath); + + return ctx; +} + +static int +opkg_finalize_intercepts(opkg_intercept_t ctx) +{ + DIR *dir; + int err = 0; + + setenv ("PATH", ctx->oldpath, 1); + free (ctx->oldpath); + + dir = opendir (ctx->statedir); + if (dir) { + struct dirent *de; + while (de = readdir (dir), de != NULL) { + char *path; + + if (de->d_name[0] == '.') + continue; + + sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name); + if (access (path, X_OK) == 0) { + const char *argv[] = {"sh", "-c", path, NULL}; + xsystem (argv); + } + free (path); + } + closedir(dir); + } else + opkg_perror(ERROR, "Failed to open dir %s", ctx->statedir); + + rm_r(ctx->statedir); + free (ctx->statedir); + free (ctx); + + return err; +} + +/* For package pkg do the following: If it is already visited, return. If not, + add it in visited list and recurse to its deps. Finally, add it to ordered + list. + pkg_vec all contains all available packages in repos. + pkg_vec visited contains packages already visited by this function, and is + used to end recursion and avoid an infinite loop on graph cycles. + pkg_vec ordered will finally contain the ordered set of packages. +*/ +static int +opkg_recurse_pkgs_in_order(pkg_t *pkg, pkg_vec_t *all, + pkg_vec_t *visited, pkg_vec_t *ordered) +{ + int j,k,l,m; + int count; + pkg_t *dep; + compound_depend_t * compound_depend; + depend_t ** possible_satisfiers; + abstract_pkg_t *abpkg; + abstract_pkg_t **dependents; + + /* If it's just an available package, that is, not installed and not even + unpacked, skip it */ + /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED + would do here. However, if there is an intermediate node (pkg) that is + configured and installed between two unpacked packages, the latter + won't be properly reordered, unless all installed/unpacked pkgs are + checked */ + if (pkg->state_status == SS_NOT_INSTALLED) + return 0; + + /* If the package has already been visited (by this function), skip it */ + for(j = 0; j < visited->len; j++) + if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) { + opkg_msg(DEBUG, "pkg %s already visited, skipping.\n", pkg->name); + return 0; + } + + pkg_vec_insert(visited, pkg); + + count = pkg->pre_depends_count + pkg->depends_count + \ + pkg->recommends_count + pkg->suggests_count; + + opkg_msg(DEBUG, "pkg %s.\n", pkg->name); + + /* Iterate over all the dependencies of pkg. For each one, find a package + that is either installed or unpacked and satisfies this dependency. + (there should only be one such package per dependency installed or + unpacked). Then recurse to the dependency package */ + for (j=0; j < count ; j++) { + compound_depend = &pkg->depends[j]; + possible_satisfiers = compound_depend->possibilities; + for (k=0; k < compound_depend->possibility_count ; k++) { + abpkg = possible_satisfiers[k]->pkg; + dependents = abpkg->provided_by->pkgs; + l = 0; + if (dependents != NULL) + while (l < abpkg->provided_by->len && dependents[l] != NULL) { + opkg_msg(DEBUG, "Descending on pkg %s.\n", + dependents [l]->name); + + /* find whether dependent l is installed or unpacked, + * and then find which package in the list satisfies it */ + for(m = 0; m < all->len; m++) { + dep = all->pkgs[m]; + if ( dep->state_status != SS_NOT_INSTALLED) + if ( ! strcmp(dep->name, dependents[l]->name)) { + opkg_recurse_pkgs_in_order(dep, all, + visited, ordered); + /* Stop the outer loop */ + l = abpkg->provided_by->len; + /* break from the inner loop */ + break; + } + } + l++; + } + } + } + + /* When all recursions from this node down, are over, and all + dependencies have been added in proper order in the ordered array, add + also the package pkg to ordered array */ + pkg_vec_insert(ordered, pkg); + + return 0; + +} + +static int +opkg_configure_packages(char *pkg_name) +{ + pkg_vec_t *all, *ordered, *visited; + int i; + pkg_t *pkg; + opkg_intercept_t ic; + int r, err = 0; + + if (conf->offline_root && !conf->force_postinstall) { + opkg_msg(INFO, "Offline root mode: not configuring unpacked packages.\n"); + return 0; + } + opkg_msg(INFO, "Configuring unpacked packages.\n"); + + all = pkg_vec_alloc(); + + pkg_hash_fetch_available(all); + + /* Reorder pkgs in order to be configured according to the Depends: tag + order */ + opkg_msg(INFO, "Reordering packages before configuring them...\n"); + ordered = pkg_vec_alloc(); + visited = pkg_vec_alloc(); + for(i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + opkg_recurse_pkgs_in_order(pkg, all, visited, ordered); + } + + ic = opkg_prep_intercepts(); + if (ic == NULL) { + err = -1; + goto error; + } + + for(i = 0; i < ordered->len; i++) { + pkg = ordered->pkgs[i]; + + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + + if (pkg->state_status == SS_UNPACKED) { + opkg_msg(NOTICE, "Configuring %s.\n", pkg->name); + r = opkg_configure(pkg); + if (r == 0) { + pkg->state_status = SS_INSTALLED; + pkg->parent->state_status = SS_INSTALLED; + pkg->state_flag &= ~SF_PREFER; + opkg_state_changed++; + } else { + err = -1; + } + } + } + + if (opkg_finalize_intercepts (ic)) + err = -1; + +error: + pkg_vec_free(all); + pkg_vec_free(ordered); + pkg_vec_free(visited); + + return err; +} + +static int +opkg_remove_cmd(int argc, char **argv); + +static int +opkg_install_cmd(int argc, char **argv) +{ + int i; + char *arg; + int err = 0; + + if (conf->force_reinstall) { + int saved_force_depends = conf->force_depends; + conf->force_depends = 1; + (void)opkg_remove_cmd(argc, argv); + conf->force_depends = saved_force_depends; + conf->force_reinstall = 0; + } + + signal(SIGINT, sigint_handler); + + /* + * Now scan through package names and install + */ + for (i=0; i < argc; i++) { + arg = argv[i]; + + opkg_msg(DEBUG2, "%s\n", arg); + if (opkg_prepare_url_for_install(arg, &argv[i])) + return -1; + } + pkg_info_preinstall_check(); + + for (i=0; i < argc; i++) { + arg = argv[i]; + if (opkg_install_by_name(arg)) { + opkg_msg(ERROR, "Cannot install package %s.\n", arg); + err = -1; + } + } + + if (opkg_configure_packages(NULL)) + err = -1; + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_upgrade_cmd(int argc, char **argv) +{ + int i; + pkg_t *pkg; + int err = 0; + + signal(SIGINT, sigint_handler); + + if (argc) { + for (i=0; i < argc; i++) { + char *arg = argv[i]; + + if (opkg_prepare_url_for_install(arg, &arg)) + return -1; + } + pkg_info_preinstall_check(); + + for (i=0; i < argc; i++) { + char *arg = argv[i]; + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(argv[i], + conf->default_dest); + if (pkg == NULL) { + opkg_msg(NOTICE, "Package %s not installed in %s.\n", + argv[i], conf->default_dest->name); + continue; + } + } else { + pkg = pkg_hash_fetch_installed_by_name(argv[i]); + } + if (pkg) { + if (opkg_upgrade_pkg(pkg)) + err = -1; + } else { + if (opkg_install_by_name(arg)) + err = -1; + } + } + } else { + pkg_vec_t *installed = pkg_vec_alloc(); + + pkg_info_preinstall_check(); + + pkg_hash_fetch_all_installed(installed); + for (i = 0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + if (opkg_upgrade_pkg(pkg)) + err = -1; + } + pkg_vec_free(installed); + } + + if (opkg_configure_packages(NULL)) + err = -1; + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_download_cmd(int argc, char **argv) +{ + int i, err = 0; + char *arg; + pkg_t *pkg; + + pkg_info_preinstall_check(); + for (i = 0; i < argc; i++) { + arg = argv[i]; + + pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg); + if (pkg == NULL) { + opkg_msg(ERROR, "Cannot find package %s.\n", arg); + continue; + } + + if (opkg_download_pkg(pkg, ".")) + err = -1; + + if (err) { + opkg_msg(ERROR, "Failed to download %s.\n", pkg->name); + } else { + opkg_msg(NOTICE, "Downloaded %s as %s.\n", + pkg->name, pkg->local_filename); + } + } + + return err; +} + + +static int +opkg_list_cmd(int argc, char **argv) +{ + int i; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_available(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + print_pkg(pkg); + } + pkg_vec_free(available); + + return 0; +} + + +static int +opkg_list_installed_cmd(int argc, char **argv) +{ + int i ; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + print_pkg(pkg); + } + + pkg_vec_free(available); + + return 0; +} + +static int +opkg_list_changed_conffiles_cmd(int argc, char **argv) +{ + int i ; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + conffile_list_elt_t *iter; + conffile_t *cf; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + if (nv_pair_list_empty(&pkg->conffiles)) + continue; + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + cf = (conffile_t *)iter->data; + if (cf->name && cf->value && conffile_has_been_modified(cf)) + printf("%s\n", cf->name); + } + } + pkg_vec_free(available); + return 0; +} + +static int +opkg_list_upgradable_cmd(int argc, char **argv) +{ + struct active_list *head = prepare_upgrade_list(); + struct active_list *node=NULL; + pkg_t *_old_pkg, *_new_pkg; + char *old_v, *new_v; + for (node = active_list_next(head, head); node;node = active_list_next(head,node)) { + _old_pkg = list_entry(node, pkg_t, list); + _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(_old_pkg->name); + if (_new_pkg == NULL) + continue; + old_v = pkg_version_str_alloc(_old_pkg); + new_v = pkg_version_str_alloc(_new_pkg); + printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v); + free(old_v); + free(new_v); + } + active_list_head_delete(head); + return 0; +} + +static int +opkg_info_status_cmd(int argc, char **argv, int installed_only) +{ + int i; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + + available = pkg_vec_alloc(); + if (installed_only) + pkg_hash_fetch_all_installed(available); + else + pkg_hash_fetch_available(available); + + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) { + continue; + } + + pkg_formatted_info(stdout, pkg); + + if (conf->verbosity >= NOTICE) { + conffile_list_elt_t *iter; + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + conffile_t *cf = (conffile_t *)iter->data; + int modified = conffile_has_been_modified(cf); + if (cf->value) + opkg_msg(INFO, "conffile=%s md5sum=%s modified=%d.\n", + cf->name, cf->value, modified); + } + } + } + pkg_vec_free(available); + + return 0; +} + +static int +opkg_info_cmd(int argc, char **argv) +{ + return opkg_info_status_cmd(argc, argv, 0); +} + +static int +opkg_status_cmd(int argc, char **argv) +{ + return opkg_info_status_cmd(argc, argv, 1); +} + +static int +opkg_configure_cmd(int argc, char **argv) +{ + int err; + char *pkg_name = NULL; + + if (argc > 0) + pkg_name = argv[0]; + + err = opkg_configure_packages(pkg_name); + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_remove_cmd(int argc, char **argv) +{ + int i, a, done, err = 0; + pkg_t *pkg; + pkg_t *pkg_to_remove; + pkg_vec_t *available; + + done = 0; + + signal(SIGINT, sigint_handler); + + pkg_info_preinstall_check(); + + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + + for (i=0; i<argc; i++) { + for (a=0; a<available->len; a++) { + pkg = available->pkgs[a]; + if (fnmatch(argv[i], pkg->name, 0)) { + continue; + } + if (conf->restrict_to_default_dest) { + pkg_to_remove = pkg_hash_fetch_installed_by_name_dest( + pkg->name, + conf->default_dest); + } else { + pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name); + } + + if (pkg_to_remove == NULL) { + opkg_msg(ERROR, "Package %s is not installed.\n", pkg->name); + continue; + } + if (pkg->state_status == SS_NOT_INSTALLED) { + opkg_msg(ERROR, "Package %s not installed.\n", pkg->name); + continue; + } + + if (opkg_remove_pkg(pkg_to_remove, 0)) + err = -1; + else + done = 1; + } + } + + pkg_vec_free(available); + + if (done == 0) + opkg_msg(NOTICE, "No packages removed.\n"); + + write_status_files_if_changed(); + return err; +} + +static int +opkg_flag_cmd(int argc, char **argv) +{ + int i; + pkg_t *pkg; + const char *flags = argv[0]; + + signal(SIGINT, sigint_handler); + + for (i=1; i < argc; i++) { + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(argv[i], + conf->default_dest); + } else { + pkg = pkg_hash_fetch_installed_by_name(argv[i]); + } + + if (pkg == NULL) { + opkg_msg(ERROR, "Package %s is not installed.\n", argv[i]); + continue; + } + if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)|| + ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) { + pkg->state_flag = pkg_state_flag_from_str(flags); + } + + /* + * Useful if a package is installed in an offline_root, and + * should be configured by opkg-cl configure at a later date. + */ + if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){ + pkg->state_status = pkg_state_status_from_str(flags); + } + + opkg_state_changed++; + opkg_msg(NOTICE, "Setting flags for package %s to %s.\n", + pkg->name, flags); + } + + write_status_files_if_changed(); + return 0; +} + +static int +opkg_files_cmd(int argc, char **argv) +{ + pkg_t *pkg; + str_list_t *files; + str_list_elt_t *iter; + char *pkg_version; + + if (argc < 1) { + return -1; + } + + pkg = pkg_hash_fetch_installed_by_name(argv[0]); + if (pkg == NULL) { + opkg_msg(ERROR, "Package %s not installed.\n", argv[0]); + return 0; + } + + files = pkg_get_installed_files(pkg); + pkg_version = pkg_version_str_alloc(pkg); + + printf("Package %s (%s) is installed on %s and has the following files:\n", + pkg->name, pkg_version, pkg->dest->name); + + for (iter=str_list_first(files); iter; iter=str_list_next(files, iter)) + printf("%s\n", (char *)iter->data); + + free(pkg_version); + pkg_free_installed_files(pkg); + + return 0; +} + +static int +opkg_depends_cmd(int argc, char **argv) +{ + int i, j, k; + int depends_count; + pkg_vec_t *available_pkgs; + compound_depend_t *cdep; + pkg_t *pkg; + char *str; + + pkg_info_preinstall_check(); + + available_pkgs = pkg_vec_alloc(); + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + + for (i=0; i<argc; i++) { + for (j=0; j<available_pkgs->len; j++) { + pkg = available_pkgs->pkgs[j]; + + if (fnmatch(argv[i], pkg->name, 0) != 0) + continue; + + depends_count = pkg->depends_count + + pkg->pre_depends_count + + pkg->recommends_count + + pkg->suggests_count; + + opkg_msg(NOTICE, "%s depends on:\n", pkg->name); + + for (k=0; k<depends_count; k++) { + cdep = &pkg->depends[k]; + + if (cdep->type != DEPEND) + continue; + + str = pkg_depend_str(pkg, k); + opkg_msg(NOTICE, "\t%s\n", str); + free(str); + } + + } + } + + pkg_vec_free(available_pkgs); + return 0; +} + +static int +pkg_mark_provides(pkg_t *pkg) +{ + int provides_count = pkg->provides_count; + abstract_pkg_t **provides = pkg->provides; + int i; + pkg->parent->state_flag |= SF_MARKED; + for (i = 0; i < provides_count; i++) { + provides[i]->state_flag |= SF_MARKED; + } + return 0; +} + +enum what_field_type { + WHATDEPENDS, + WHATCONFLICTS, + WHATPROVIDES, + WHATREPLACES, + WHATRECOMMENDS, + WHATSUGGESTS +}; + +static int +opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive, int argc, char **argv) +{ + depend_t *possibility; + compound_depend_t *cdep; + pkg_vec_t *available_pkgs; + pkg_t *pkg; + int i, j, k, l; + int changed, count; + const char *rel_str = NULL; + char *ver; + + switch (what_field_type) { + case DEPEND: rel_str = "depends on"; break; + case CONFLICTS: rel_str = "conflicts with"; break; + case SUGGEST: rel_str = "suggests"; break; + case RECOMMEND: rel_str = "recommends"; break; + default: return -1; + } + + available_pkgs = pkg_vec_alloc(); + + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + + /* mark the root set */ + pkg_vec_clear_marks(available_pkgs); + opkg_msg(NOTICE, "Root set:\n"); + for (i = 0; i < argc; i++) + pkg_vec_mark_if_matches(available_pkgs, argv[i]); + + for (i = 0; i < available_pkgs->len; i++) { + pkg = available_pkgs->pkgs[i]; + if (pkg->state_flag & SF_MARKED) { + /* mark the parent (abstract) package */ + pkg_mark_provides(pkg); + opkg_msg(NOTICE, " %s\n", pkg->name); + } + } + + opkg_msg(NOTICE, "What %s root set\n", rel_str); + do { + changed = 0; + + for (j=0; j<available_pkgs->len; j++) { + + pkg = available_pkgs->pkgs[j]; + count = ((what_field_type == CONFLICTS) + ? pkg->conflicts_count + : pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count); + + /* skip this package if it is already marked */ + if (pkg->parent->state_flag & SF_MARKED) + continue; + + for (k=0; k<count; k++) { + cdep = (what_field_type == CONFLICTS) + ? &pkg->conflicts[k] + : &pkg->depends[k]; + + if (what_field_type != cdep->type) + continue; + + for (l=0; l<cdep->possibility_count; l++) { + possibility = cdep->possibilities[l]; + + if ((possibility->pkg->state_flag + & SF_MARKED) + != SF_MARKED) + continue; + + /* mark the depending package so we + * won't visit it again */ + pkg->state_flag |= SF_MARKED; + pkg_mark_provides(pkg); + changed++; + + ver = pkg_version_str_alloc(pkg); + opkg_msg(NOTICE, "\t%s %s\t%s %s", + pkg->name, + ver, + rel_str, + possibility->pkg->name); + free(ver); + if (possibility->version) { + opkg_msg(NOTICE, " (%s%s)", + constraint_to_str(possibility->constraint), + possibility->version); + } + if (!pkg_dependence_satisfiable(possibility)) + opkg_msg(NOTICE, + " unsatisfiable"); + opkg_message(NOTICE, "\n"); + goto next_package; + } + } +next_package: + ; + } + } while (changed && recursive); + + pkg_vec_free(available_pkgs); + + return 0; +} + +static int +opkg_whatdepends_recursively_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv); +} + +static int +opkg_whatdepends_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv); +} + +static int +opkg_whatsuggests_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv); +} + +static int +opkg_whatrecommends_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv); +} + +static int +opkg_whatconflicts_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv); +} + +static int +opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc, char **argv) +{ + + if (argc > 0) { + pkg_vec_t *available_pkgs = pkg_vec_alloc(); + const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces"); + int i; + + pkg_info_preinstall_check(); + + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + for (i = 0; i < argc; i++) { + const char *target = argv[i]; + int j; + + opkg_msg(NOTICE, "What %s %s\n", + rel_str, target); + for (j = 0; j < available_pkgs->len; j++) { + pkg_t *pkg = available_pkgs->pkgs[j]; + int k; + int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count; + for (k = 0; k < count; k++) { + abstract_pkg_t *apkg = + ((what_field_type == WHATPROVIDES) + ? pkg->provides[k] + : pkg->replaces[k]); + if (fnmatch(target, apkg->name, 0) == 0) { + opkg_msg(NOTICE, " %s", pkg->name); + if (strcmp(target, apkg->name) != 0) + opkg_msg(NOTICE, "\t%s %s\n", + rel_str, apkg->name); + opkg_message(NOTICE, "\n"); + } + } + } + } + pkg_vec_free(available_pkgs); + } + return 0; +} + +static int +opkg_whatprovides_cmd(int argc, char **argv) +{ + return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv); +} + +static int +opkg_whatreplaces_cmd(int argc, char **argv) +{ + return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv); +} + +static int +opkg_search_cmd(int argc, char **argv) +{ + int i; + + pkg_vec_t *installed; + pkg_t *pkg; + str_list_t *installed_files; + str_list_elt_t *iter; + char *installed_file; + + if (argc < 1) { + return -1; + } + + installed = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(installed); + pkg_vec_sort(installed, pkg_compare_names); + + for (i=0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + + installed_files = pkg_get_installed_files(pkg); + + for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) { + installed_file = (char *)iter->data; + if (fnmatch(argv[0], installed_file, 0)==0) + print_pkg(pkg); + } + + pkg_free_installed_files(pkg); + } + + pkg_vec_free(installed); + + return 0; +} + +static int +opkg_compare_versions_cmd(int argc, char **argv) +{ + if (argc == 3) { + /* this is a bit gross */ + struct pkg p1, p2; + parse_version(&p1, argv[0]); + parse_version(&p2, argv[2]); + return pkg_version_satisfied(&p1, &p2, argv[1]); + } else { + opkg_msg(ERROR, + "opkg compare_versions <v1> <op> <v2>\n" + "<op> is one of <= >= << >> =\n"); + return -1; + } +} + +static int +opkg_print_architecture_cmd(int argc, char **argv) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l, &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + printf("arch %s %s\n", nv->name, nv->value); + } + return 0; +} + + +/* XXX: CLEANUP: The usage strings should be incorporated into this + array for easier maintenance */ +static opkg_cmd_t cmds[] = { + {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd, PFM_SOURCE}, + {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE}, + {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE}, + {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE}, + {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE}, + {"list_changed_conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE}, + {"list-changed-conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE}, + {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd, 0}, + {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd, PFM_DESCRIPTION|PFM_SOURCE}, +}; + +opkg_cmd_t * +opkg_cmd_find(const char *name) +{ + int i; + opkg_cmd_t *cmd; + int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t); + + for (i=0; i < num_cmds; i++) { + cmd = &cmds[i]; + if (strcmp(name, cmd->name) == 0) + return cmd; + } + + return NULL; +} + +int +opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv) +{ + return (cmd->fun)(argc, argv); +} diff --git a/src/libopkg/.svn/text-base/opkg_cmd.h.svn-base b/src/libopkg/.svn/text-base/opkg_cmd.h.svn-base new file mode 100644 index 0000000..9ca42ff --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_cmd.h.svn-base @@ -0,0 +1,36 @@ +/* opkg_cmd.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_CMD_H +#define OPKG_CMD_H + +typedef int (*opkg_cmd_fun_t)(int argc, const char **argv); + +struct opkg_cmd +{ + const char *name; + int requires_args; + opkg_cmd_fun_t fun; + unsigned int pfm; /* package field mask */ +}; +typedef struct opkg_cmd opkg_cmd_t; + +opkg_cmd_t *opkg_cmd_find(const char *name); +int opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv); + +extern int opkg_state_changed; +#endif diff --git a/src/libopkg/.svn/text-base/opkg_conf.c.svn-base b/src/libopkg/.svn/text-base/opkg_conf.c.svn-base new file mode 100644 index 0000000..4711ce7 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_conf.c.svn-base @@ -0,0 +1,688 @@ +/* opkg_conf.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <glob.h> +#include <unistd.h> + +#include "opkg_conf.h" +#include "pkg_vec.h" +#include "pkg.h" +#include "xregex.h" +#include "sprintf_alloc.h" +#include "opkg_message.h" +#include "file_util.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +static int lock_fd; +static char *lock_file = NULL; + +static opkg_conf_t _conf; +opkg_conf_t *conf = &_conf; + +/* + * Config file options + */ +opkg_option_t options[] = { + { "cache", OPKG_OPT_TYPE_STRING, &_conf.cache}, + { "force_defaults", OPKG_OPT_TYPE_BOOL, &_conf.force_defaults }, + { "force_maintainer", OPKG_OPT_TYPE_BOOL, &_conf.force_maintainer }, + { "force_depends", OPKG_OPT_TYPE_BOOL, &_conf.force_depends }, + { "force_overwrite", OPKG_OPT_TYPE_BOOL, &_conf.force_overwrite }, + { "force_downgrade", OPKG_OPT_TYPE_BOOL, &_conf.force_downgrade }, + { "force_reinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_reinstall }, + { "force_space", OPKG_OPT_TYPE_BOOL, &_conf.force_space }, + { "force_postinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_postinstall }, + { "check_signature", OPKG_OPT_TYPE_BOOL, &_conf.check_signature }, + { "ftp_proxy", OPKG_OPT_TYPE_STRING, &_conf.ftp_proxy }, + { "http_proxy", OPKG_OPT_TYPE_STRING, &_conf.http_proxy }, + { "no_proxy", OPKG_OPT_TYPE_STRING, &_conf.no_proxy }, + { "test", OPKG_OPT_TYPE_BOOL, &_conf.noaction }, + { "noaction", OPKG_OPT_TYPE_BOOL, &_conf.noaction }, + { "download_only", OPKG_OPT_TYPE_BOOL, &_conf.download_only }, + { "nodeps", OPKG_OPT_TYPE_BOOL, &_conf.nodeps }, + { "offline_root", OPKG_OPT_TYPE_STRING, &_conf.offline_root }, + { "overlay_root", OPKG_OPT_TYPE_STRING, &_conf.overlay_root }, + { "proxy_passwd", OPKG_OPT_TYPE_STRING, &_conf.proxy_passwd }, + { "proxy_user", OPKG_OPT_TYPE_STRING, &_conf.proxy_user }, + { "query-all", OPKG_OPT_TYPE_BOOL, &_conf.query_all }, + { "tmp_dir", OPKG_OPT_TYPE_STRING, &_conf.tmp_dir }, + { "verbosity", OPKG_OPT_TYPE_INT, &_conf.verbosity }, +#if defined(HAVE_OPENSSL) + { "signature_ca_file", OPKG_OPT_TYPE_STRING, &_conf.signature_ca_file }, + { "signature_ca_path", OPKG_OPT_TYPE_STRING, &_conf.signature_ca_path }, +#endif +#if defined(HAVE_PATHFINDER) + { "check_x509_path", OPKG_OPT_TYPE_BOOL, &_conf.check_x509_path }, +#endif +#if defined(HAVE_SSLCURL) && defined(HAVE_CURL) + { "ssl_engine", OPKG_OPT_TYPE_STRING, &_conf.ssl_engine }, + { "ssl_cert", OPKG_OPT_TYPE_STRING, &_conf.ssl_cert }, + { "ssl_cert_type", OPKG_OPT_TYPE_STRING, &_conf.ssl_cert_type }, + { "ssl_key", OPKG_OPT_TYPE_STRING, &_conf.ssl_key }, + { "ssl_key_type", OPKG_OPT_TYPE_STRING, &_conf.ssl_key_type }, + { "ssl_key_passwd", OPKG_OPT_TYPE_STRING, &_conf.ssl_key_passwd }, + { "ssl_ca_file", OPKG_OPT_TYPE_STRING, &_conf.ssl_ca_file }, + { "ssl_ca_path", OPKG_OPT_TYPE_STRING, &_conf.ssl_ca_path }, + { "ssl_dont_verify_peer", OPKG_OPT_TYPE_BOOL, &_conf.ssl_dont_verify_peer }, +#endif + { NULL, 0, NULL } +}; + +static int +resolve_pkg_dest_list(void) +{ + nv_pair_list_elt_t *iter; + nv_pair_t *nv_pair; + pkg_dest_t *dest; + char *root_dir; + + for (iter = nv_pair_list_first(&conf->tmp_dest_list); iter; + iter = nv_pair_list_next(&conf->tmp_dest_list, iter)) { + nv_pair = (nv_pair_t *)iter->data; + + if (conf->offline_root) { + sprintf_alloc(&root_dir, "%s%s", conf->offline_root, nv_pair->value); + } else { + root_dir = xstrdup(nv_pair->value); + } + + dest = pkg_dest_list_append(&conf->pkg_dest_list, nv_pair->name, root_dir, conf->lists_dir); + free(root_dir); + + if (conf->default_dest == NULL) + conf->default_dest = dest; + + if (conf->dest_str && !strcmp(dest->name, conf->dest_str)) { + conf->default_dest = dest; + conf->restrict_to_default_dest = 1; + } + } + + if (conf->dest_str && !conf->restrict_to_default_dest) { + opkg_msg(ERROR, "Unknown dest name: `%s'.\n", conf->dest_str); + return -1; + } + + return 0; +} + +static int +opkg_conf_set_option(const char *name, const char *value) +{ + int i = 0; + + while (options[i].name) { + if (strcmp(options[i].name, name) == 0) { + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + if (*(int *)options[i].value) { + opkg_msg(ERROR, "Duplicate boolean option %s, " + "leaving this option on.\n", name); + return 0; + } + *((int * const)options[i].value) = 1; + return 0; + case OPKG_OPT_TYPE_INT: + if (value) { + if (*(int *)options[i].value) { + opkg_msg(ERROR, "Duplicate option %s, " + "using first seen value \"%d\".\n", + name, *((int *)options[i].value)); + return 0; + } + *((int * const)options[i].value) = atoi(value); + return 0; + } else { + opkg_msg(ERROR, "Option %s needs an argument\n", + name); + return -1; + } + case OPKG_OPT_TYPE_STRING: + if (value) { + if (*(char **)options[i].value) { + opkg_msg(ERROR, "Duplicate option %s, " + "using first seen value \"%s\".\n", + name, *((char **)options[i].value)); + return 0; + } + *((char ** const)options[i].value) = xstrdup(value); + return 0; + } else { + opkg_msg(ERROR, "Option %s needs an argument\n", + name); + return -1; + } + } + } + i++; + } + + opkg_msg(ERROR, "Unrecognized option: %s=%s\n", name, value); + return -1; +} + +static int +opkg_conf_parse_file(const char *filename, + pkg_src_list_t *pkg_src_list, + pkg_src_list_t *dist_src_list) +{ + int line_num = 0; + int err = 0; + FILE *file; + regex_t valid_line_re, comment_re; +#define regmatch_size 14 + regmatch_t regmatch[regmatch_size]; + + file = fopen(filename, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open %s", filename); + err = -1; + goto err0; + } + + opkg_msg(INFO, "Loading conf file %s.\n", filename); + + err = xregcomp(&comment_re, + "^[[:space:]]*(#.*|[[:space:]]*)$", + REG_EXTENDED); + if (err) + goto err1; + + err = xregcomp(&valid_line_re, + "^[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "([[:space:]]+([^[:space:]]+))?([[:space:]]+(.*))?[[:space:]]*$", + REG_EXTENDED); + if (err) + goto err2; + + while(1) { + char *line; + char *type, *name, *value, *extra; + + line_num++; + + line = file_read_line_alloc(file); + if (line == NULL) + break; + + if (regexec(&comment_re, line, 0, 0, 0) == 0) + goto NEXT_LINE; + + if (regexec(&valid_line_re, line, regmatch_size, regmatch, 0) == REG_NOMATCH) { + opkg_msg(ERROR, "%s:%d: Ignoring invalid line: `%s'\n", + filename, line_num, line); + goto NEXT_LINE; + } + + /* This has to be so ugly to deal with optional quotation marks */ + if (regmatch[2].rm_so > 0) { + type = xstrndup(line + regmatch[2].rm_so, + regmatch[2].rm_eo - regmatch[2].rm_so); + } else { + type = xstrndup(line + regmatch[3].rm_so, + regmatch[3].rm_eo - regmatch[3].rm_so); + } + + if (regmatch[5].rm_so > 0) { + name = xstrndup(line + regmatch[5].rm_so, + regmatch[5].rm_eo - regmatch[5].rm_so); + } else { + name = xstrndup(line + regmatch[6].rm_so, + regmatch[6].rm_eo - regmatch[6].rm_so); + } + + if (regmatch[8].rm_so > 0) { + value = xstrndup(line + regmatch[8].rm_so, + regmatch[8].rm_eo - regmatch[8].rm_so); + } else { + value = xstrndup(line + regmatch[9].rm_so, + regmatch[9].rm_eo - regmatch[9].rm_so); + } + + extra = NULL; + if (regmatch[11].rm_so > 0) { + if (regmatch[13].rm_so > 0 && regmatch[13].rm_so!=regmatch[13].rm_eo ) + extra = xstrndup (line + regmatch[11].rm_so, + regmatch[13].rm_eo - regmatch[11].rm_so); + else + extra = xstrndup (line + regmatch[11].rm_so, + regmatch[11].rm_eo - regmatch[11].rm_so); + } + + if (regmatch[13].rm_so!=regmatch[13].rm_eo && strncmp(type, "dist", 4)!=0) { + opkg_msg(ERROR, "%s:%d: Ignoring config line with trailing garbage: `%s'\n", + filename, line_num, line); + } else { + + /* We use the conf->tmp_dest_list below instead of + conf->pkg_dest_list because we might encounter an + offline_root option later and that would invalidate the + directories we would have computed in + pkg_dest_list_init. (We do a similar thing with + tmp_src_nv_pair_list for sake of symmetry.) */ + if (strcmp(type, "option") == 0) { + opkg_conf_set_option(name, value); + } else if (strcmp(type, "dist") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) dist_src_list, name)) { + pkg_src_list_append (dist_src_list, name, value, extra, 0); + } else { + opkg_msg(ERROR, "Duplicate dist declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "dist/gz") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) dist_src_list, name)) { + pkg_src_list_append (dist_src_list, name, value, extra, 1); + } else { + opkg_msg(ERROR, "Duplicate dist declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "src") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) pkg_src_list, name)) { + pkg_src_list_append (pkg_src_list, name, value, extra, 0); + } else { + opkg_msg(ERROR, "Duplicate src declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "src/gz") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) pkg_src_list, name)) { + pkg_src_list_append (pkg_src_list, name, value, extra, 1); + } else { + opkg_msg(ERROR, "Duplicate src declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "dest") == 0) { + nv_pair_list_append(&conf->tmp_dest_list, name, value); + } else if (strcmp(type, "lists_dir") == 0) { + conf->lists_dir = xstrdup(value); + } else if (strcmp(type, "arch") == 0) { + opkg_msg(INFO, "Supported arch %s priority (%s)\n", name, value); + if (!value) { + opkg_msg(NOTICE, "No priority given for architecture %s," + "defaulting to 10\n", name); + value = xstrdup("10"); + } + nv_pair_list_append(&conf->arch_list, name, value); + } else { + opkg_msg(ERROR, "%s:%d: Ignoring invalid line: `%s'\n", + filename, line_num, line); + } + + } + + free(type); + free(name); + free(value); + if (extra) + free(extra); + +NEXT_LINE: + free(line); + } + + regfree(&valid_line_re); +err2: + regfree(&comment_re); +err1: + if (fclose(file) == EOF) { + opkg_perror(ERROR, "Couldn't close %s", filename); + err = -1; + } +err0: + return err; +} + +int +opkg_conf_write_status_files(void) +{ + pkg_dest_list_elt_t *iter; + pkg_dest_t *dest; + pkg_vec_t *all; + pkg_t *pkg; + int i, ret = 0; + + if (conf->noaction) + return 0; + + list_for_each_entry(iter, &conf->pkg_dest_list.head, node) { + dest = (pkg_dest_t *)iter->data; + + dest->status_fp = fopen(dest->status_file_name, "w"); + if (dest->status_fp == NULL && errno != EROFS) { + opkg_perror(ERROR, "Can't open status file %s", + dest->status_file_name); + ret = -1; + } + } + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + for(i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + /* We don't need most uninstalled packages in the status file */ + if (pkg->state_status == SS_NOT_INSTALLED + && (pkg->state_want == SW_UNKNOWN + || (pkg->state_want == SW_DEINSTALL + && pkg->state_flag != SF_HOLD) + || pkg->state_want == SW_PURGE)) { + continue; + } + if (pkg->dest == NULL) { + opkg_msg(ERROR, "Internal error: package %s has a NULL dest\n", + pkg->name); + continue; + } + if (pkg->dest->status_fp) + pkg_print_status(pkg, pkg->dest->status_fp); + } + + pkg_vec_free(all); + + list_for_each_entry(iter, &conf->pkg_dest_list.head, node) { + dest = (pkg_dest_t *)iter->data; + if (dest->status_fp && fclose(dest->status_fp) == EOF) { + opkg_perror(ERROR, "Couldn't close %s", dest->status_file_name); + ret = -1; + } + } + + return ret; +} + + +char * +root_filename_alloc(char *filename) +{ + char *root_filename; + sprintf_alloc(&root_filename, "%s%s", + (conf->offline_root ? conf->offline_root : ""), filename); + return root_filename; +} + +static int +glob_errfunc(const char *epath, int eerrno) +{ + if (eerrno == ENOENT) + /* If leading dir does not exist, we get GLOB_NOMATCH. */ + return 0; + + opkg_msg(ERROR, "glob failed for %s: %s\n", epath, strerror(eerrno)); + return 0; +} + +int +opkg_conf_init(void) +{ + pkg_src_list_init(&conf->pkg_src_list); + pkg_src_list_init(&conf->dist_src_list); + pkg_dest_list_init(&conf->pkg_dest_list); + pkg_dest_list_init(&conf->tmp_dest_list); + nv_pair_list_init(&conf->arch_list); + + return 0; +} + +int +opkg_conf_load(void) +{ + int i, glob_ret; + char *tmp, *tmp_dir_base, **tmp_val; + glob_t globbuf; + char *etc_opkg_conf_pattern; + + conf->restrict_to_default_dest = 0; + conf->default_dest = NULL; +#if defined(HAVE_PATHFINDER) + conf->check_x509_path = 1; +#endif + + if (!conf->offline_root) + conf->offline_root = xstrdup(getenv("OFFLINE_ROOT")); + + if (conf->conf_file) { + struct stat st; + if (stat(conf->conf_file, &st) == -1) { + opkg_perror(ERROR, "Couldn't stat %s", conf->conf_file); + goto err0; + } + if (opkg_conf_parse_file(conf->conf_file, + &conf->pkg_src_list, &conf->dist_src_list)) + goto err1; + } + + if (conf->offline_root) + sprintf_alloc(&etc_opkg_conf_pattern, "%s/etc/opkg/*.conf", conf->offline_root); + else { + const char *conf_file_dir = getenv("OPKG_CONF_DIR"); + if (conf_file_dir == NULL) + conf_file_dir = OPKG_CONF_DEFAULT_CONF_FILE_DIR; + sprintf_alloc(&etc_opkg_conf_pattern, "%s/*.conf", conf_file_dir); + } + + memset(&globbuf, 0, sizeof(globbuf)); + glob_ret = glob(etc_opkg_conf_pattern, 0, glob_errfunc, &globbuf); + if (glob_ret && glob_ret != GLOB_NOMATCH) { + free(etc_opkg_conf_pattern); + globfree(&globbuf); + goto err1; + } + + free(etc_opkg_conf_pattern); + + for (i = 0; i < globbuf.gl_pathc; i++) { + if (globbuf.gl_pathv[i]) + if (conf->conf_file && + !strcmp(conf->conf_file, globbuf.gl_pathv[i])) + continue; + if ( opkg_conf_parse_file(globbuf.gl_pathv[i], + &conf->pkg_src_list, &conf->dist_src_list)<0) { + globfree(&globbuf); + goto err1; + } + } + + globfree(&globbuf); + + if (conf->offline_root) + sprintf_alloc (&lock_file, "%s/%s", conf->offline_root, OPKGLOCKFILE); + else + sprintf_alloc (&lock_file, "%s", OPKGLOCKFILE); + + lock_fd = creat(lock_file, S_IRUSR | S_IWUSR | S_IRGRP); + if (lock_fd == -1) { + opkg_perror(ERROR, "Could not create lock file %s", lock_file); + goto err2; + } + + if (lockf(lock_fd, F_TLOCK, (off_t)0) == -1) { + opkg_perror(ERROR, "Could not lock %s", lock_file); + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + lock_fd = -1; + goto err2; + } + + if (conf->tmp_dir) + tmp_dir_base = conf->tmp_dir; + else + tmp_dir_base = getenv("TMPDIR"); + + sprintf_alloc(&tmp, "%s/%s", + tmp_dir_base ? tmp_dir_base : OPKG_CONF_DEFAULT_TMP_DIR_BASE, + OPKG_CONF_TMP_DIR_SUFFIX); + if (conf->tmp_dir) + free(conf->tmp_dir); + conf->tmp_dir = mkdtemp(tmp); + if (conf->tmp_dir == NULL) { + opkg_perror(ERROR, "Creating temp dir %s failed", tmp); + goto err3; + } + + pkg_hash_init(); + hash_table_init("file-hash", &conf->file_hash, OPKG_CONF_DEFAULT_HASH_LEN); + hash_table_init("obs-file-hash", &conf->obs_file_hash, OPKG_CONF_DEFAULT_HASH_LEN/16); + + if (conf->lists_dir == NULL) + conf->lists_dir = xstrdup(OPKG_CONF_LISTS_DIR); + + if (conf->offline_root) { + sprintf_alloc(&tmp, "%s/%s", conf->offline_root, conf->lists_dir); + free(conf->lists_dir); + conf->lists_dir = tmp; + } + + /* if no architectures were defined, then default all, noarch, and host architecture */ + if (nv_pair_list_empty(&conf->arch_list)) { + nv_pair_list_append(&conf->arch_list, "all", "1"); + nv_pair_list_append(&conf->arch_list, "noarch", "1"); + nv_pair_list_append(&conf->arch_list, HOST_CPU_STR, "10"); + } + + /* Even if there is no conf file, we'll need at least one dest. */ + if (nv_pair_list_empty(&conf->tmp_dest_list)) { + nv_pair_list_append(&conf->tmp_dest_list, + OPKG_CONF_DEFAULT_DEST_NAME, + OPKG_CONF_DEFAULT_DEST_ROOT_DIR); + } + + if (resolve_pkg_dest_list()) + goto err4; + + nv_pair_list_deinit(&conf->tmp_dest_list); + + return 0; + + +err4: + free(conf->lists_dir); + + pkg_hash_deinit(); + hash_table_deinit(&conf->file_hash); + hash_table_deinit(&conf->obs_file_hash); + + if (rmdir(conf->tmp_dir) == -1) + opkg_perror(ERROR, "Couldn't remove dir %s", conf->tmp_dir); +err3: + if (lockf(lock_fd, F_ULOCK, (off_t)0) == -1) + opkg_perror(ERROR, "Couldn't unlock %s", lock_file); + + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + if (unlink(lock_file) == -1) + opkg_perror(ERROR, "Couldn't unlink %s", lock_file); +err2: + if (lock_file) { + free(lock_file); + lock_file = NULL; + } +err1: + pkg_src_list_deinit(&conf->pkg_src_list); + pkg_src_list_deinit(&conf->dist_src_list); + pkg_dest_list_deinit(&conf->pkg_dest_list); + nv_pair_list_deinit(&conf->arch_list); + + for (i=0; options[i].name; i++) { + if (options[i].type == OPKG_OPT_TYPE_STRING) { + tmp_val = (char **)options[i].value; + if (*tmp_val) { + free(*tmp_val); + *tmp_val = NULL; + } + } + } +err0: + nv_pair_list_deinit(&conf->tmp_dest_list); + if (conf->dest_str) + free(conf->dest_str); + if (conf->conf_file) + free(conf->conf_file); + + return -1; +} + +void +opkg_conf_deinit(void) +{ + int i; + char **tmp; + + if (conf->tmp_dir) + rm_r(conf->tmp_dir); + + if (conf->lists_dir) + free(conf->lists_dir); + + if (conf->dest_str) + free(conf->dest_str); + + if (conf->conf_file) + free(conf->conf_file); + + pkg_src_list_deinit(&conf->pkg_src_list); + pkg_src_list_deinit(&conf->dist_src_list); + pkg_dest_list_deinit(&conf->pkg_dest_list); + nv_pair_list_deinit(&conf->arch_list); + + for (i=0; options[i].name; i++) { + if (options[i].type == OPKG_OPT_TYPE_STRING) { + tmp = (char **)options[i].value; + if (*tmp) { + free(*tmp); + *tmp = NULL; + } + } + } + + if (conf->verbosity >= DEBUG) { + hash_print_stats(&conf->pkg_hash); + hash_print_stats(&conf->file_hash); + hash_print_stats(&conf->obs_file_hash); + } + + pkg_hash_deinit(); + hash_table_deinit(&conf->file_hash); + hash_table_deinit(&conf->obs_file_hash); + + if (lock_fd != -1) { + if (lockf(lock_fd, F_ULOCK, (off_t)0) == -1) + opkg_perror(ERROR, "Couldn't unlock %s", lock_file); + + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + + } + + if (lock_file) { + if (unlink(lock_file) == -1) + opkg_perror(ERROR, "Couldn't unlink %s", lock_file); + + free(lock_file); + } +} diff --git a/src/libopkg/.svn/text-base/opkg_conf.h.svn-base b/src/libopkg/.svn/text-base/opkg_conf.h.svn-base new file mode 100644 index 0000000..3a60bc5 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_conf.h.svn-base @@ -0,0 +1,145 @@ +/* opkg_conf.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_CONF_H +#define OPKG_CONF_H + +typedef struct opkg_conf opkg_conf_t; +extern opkg_conf_t *conf; + +#include "config.h" + +#include <stdarg.h> + +#include "hash_table.h" +#include "pkg_src_list.h" +#include "pkg_dest_list.h" +#include "nv_pair_list.h" + +#define OPKG_CONF_DEFAULT_TMP_DIR_BASE "/tmp" +#define OPKG_CONF_TMP_DIR_SUFFIX "opkg-XXXXXX" +#define OPKG_CONF_LISTS_DIR OPKG_STATE_DIR_PREFIX "/lists" + +#define OPKG_CONF_DEFAULT_CONF_FILE_DIR OPKGETCDIR"/opkg" + +/* In case the config file defines no dest */ +#define OPKG_CONF_DEFAULT_DEST_NAME "root" +#define OPKG_CONF_DEFAULT_DEST_ROOT_DIR "/" + +#define OPKG_CONF_DEFAULT_HASH_LEN 1024 + +struct opkg_conf +{ + pkg_src_list_t pkg_src_list; + pkg_src_list_t dist_src_list; + pkg_dest_list_t pkg_dest_list; + pkg_dest_list_t tmp_dest_list; + nv_pair_list_t arch_list; + + int restrict_to_default_dest; + pkg_dest_t *default_dest; + char *dest_str; + + char *conf_file; + + char *tmp_dir; + char *lists_dir; + + unsigned int pfm; /* package field mask */ + + /* For libopkg users to capture messages. */ + void (*opkg_vmessage)(int, const char *fmt, va_list ap); + + /* options */ + int autoremove; + int force_depends; + int force_defaults; + int force_maintainer; + int force_overwrite; + int force_downgrade; + int force_reinstall; + int force_space; + int force_removal_of_dependent_packages; + int force_removal_of_essential_packages; + int force_postinstall; + int force_remove; + int check_signature; + int nodeps; /* do not follow dependencies */ + char *offline_root; + char *overlay_root; + int query_all; + int verbosity; + int noaction; + int download_only; + char *cache; + +#ifdef HAVE_SSLCURL + /* some options could be used by + * wget if curl support isn't builtin + * If someone want to try... + */ + char *ssl_engine; + char *ssl_cert; + char *ssl_cert_type; + char *ssl_key; + char *ssl_key_type; + char *ssl_key_passwd; + char *ssl_ca_file; + char *ssl_ca_path; + int ssl_dont_verify_peer; +#endif +#ifdef HAVE_PATHFINDER + int check_x509_path; +#endif + + /* proxy options */ + char *http_proxy; + char *ftp_proxy; + char *no_proxy; + char *proxy_user; + char *proxy_passwd; + + char *signature_ca_file; + char *signature_ca_path; + + hash_table_t pkg_hash; + hash_table_t file_hash; + hash_table_t obs_file_hash; +}; + +enum opkg_option_type { + OPKG_OPT_TYPE_BOOL, + OPKG_OPT_TYPE_INT, + OPKG_OPT_TYPE_STRING +}; +typedef enum opkg_option_type opkg_option_type_t; + +typedef struct opkg_option opkg_option_t; +struct opkg_option { + const char *name; + const opkg_option_type_t type; + void * const value; +}; + +int opkg_conf_init(void); +int opkg_conf_load(void); +void opkg_conf_deinit(void); + +int opkg_conf_write_status_files(void); +char *root_filename_alloc(char *filename); + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_configure.c.svn-base b/src/libopkg/.svn/text-base/opkg_configure.c.svn-base new file mode 100644 index 0000000..719da5a --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_configure.c.svn-base @@ -0,0 +1,44 @@ +/* opkg_configure.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> + +#include "sprintf_alloc.h" +#include "opkg_configure.h" +#include "opkg_message.h" +#include "opkg_cmd.h" + +int +opkg_configure(pkg_t *pkg) +{ + int err; + + /* DPKG_INCOMPATIBILITY: + dpkg actually does some conffile handling here, rather than at the + end of opkg_install(). Do we care? */ + /* DPKG_INCOMPATIBILITY: + dpkg actually includes a version number to this script call */ + + err = pkg_run_script(pkg, "postinst", "configure"); + if (err) { + opkg_msg(ERROR, "%s.postinst returned %d.\n", pkg->name, err); + return err; + } + + return 0; +} + diff --git a/src/libopkg/.svn/text-base/opkg_configure.h.svn-base b/src/libopkg/.svn/text-base/opkg_configure.h.svn-base new file mode 100644 index 0000000..ff01ff3 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_configure.h.svn-base @@ -0,0 +1,25 @@ +/* opkg_configure.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_CONFIGURE_H +#define OPKG_CONFIGURE_H + +#include "pkg.h" + +int opkg_configure(pkg_t *pkg); + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_defines.h.svn-base b/src/libopkg/.svn/text-base/opkg_defines.h.svn-base new file mode 100644 index 0000000..090d7d4 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_defines.h.svn-base @@ -0,0 +1,35 @@ +/* opkg_defines.h - the opkg package management system + + Copyright (C) 2008 OpenMoko 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, 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. +*/ + +#ifndef OPKG_DEFINES_H +#define OPKG_DEFINES_H + +#define OPKG_PKG_EXTENSION ".opk" +#define IPKG_PKG_EXTENSION ".ipk" +#define DPKG_PKG_EXTENSION ".deb" + +#define OPKG_LEGAL_PKG_NAME_CHARS "abcdefghijklmnopqrstuvwxyz0123456789.+-" +#define OPKG_PKG_VERSION_SEP_CHAR '_' + +#define OPKG_STATE_DIR_PREFIX OPKGLIBDIR"/opkg" +#define OPKG_LISTS_DIR_SUFFIX "lists" +#define OPKG_INFO_DIR_SUFFIX "info" +#define OPKG_STATUS_FILE_SUFFIX "status" + +#define OPKG_BACKUP_SUFFIX "-opkg.backup" + +#define OPKG_LIST_DESCRIPTION_LENGTH 128 + +#endif /* OPKG_DEFINES_H */ diff --git a/src/libopkg/.svn/text-base/opkg_download.c.svn-base b/src/libopkg/.svn/text-base/opkg_download.c.svn-base new file mode 100644 index 0000000..e53e64e --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_download.c.svn-base @@ -0,0 +1,679 @@ +/* vi: set noexpandtab sw=4 sts=4: */ +/* opkg_download.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + Copyright (C) 2008 OpenMoko 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <libgen.h> + +#include "opkg_download.h" +#include "opkg_message.h" + +#include "sprintf_alloc.h" +#include "xsystem.h" +#include "file_util.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +#ifdef HAVE_CURL +#include <curl/curl.h> +#endif + +#if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL) +#include <openssl/conf.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/ssl.h> +#endif + +#if defined(HAVE_GPGME) +#include <gpgme.h> +#elif defined(HAVE_OPENSSL) +#include <openssl/bio.h> +#include <openssl/objects.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/hmac.h> +#endif + +#ifdef HAVE_PATHFINDER +#include "opkg_pathfinder.h" +#endif + +#if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL) +static void openssl_init(void); +#endif + +#ifdef HAVE_OPENSSL +static X509_STORE *setup_verify(char *CAfile, char *CApath); +#endif + +#ifdef HAVE_CURL +/* + * Make curl an instance variable so we don't have to instanciate it + * each time + */ +static CURL *curl = NULL; +static CURL *opkg_curl_init(curl_progress_func cb, void *data); +#endif + +static int +str_starts_with(const char *str, const char *prefix) +{ + return (strncmp(str, prefix, strlen(prefix)) == 0); +} + +int +opkg_download(const char *src, const char *dest_file_name, + curl_progress_func cb, void *data, const short hide_error) +{ + int err = 0; + + char *src_basec = xstrdup(src); + char *src_base = basename(src_basec); + char *tmp_file_location; + + opkg_msg(NOTICE,"Downloading %s.\n", src); + + if (str_starts_with(src, "file:")) { + const char *file_src = src + 5; + opkg_msg(INFO, "Copying %s to %s...", file_src, dest_file_name); + err = file_copy(file_src, dest_file_name); + opkg_msg(INFO, "Done.\n"); + free(src_basec); + return err; + } + + sprintf_alloc(&tmp_file_location, "%s/%s", conf->tmp_dir, src_base); + free(src_basec); + err = unlink(tmp_file_location); + if (err && errno != ENOENT) { + opkg_perror(ERROR, "Failed to unlink %s", tmp_file_location); + free(tmp_file_location); + return -1; + } + + if (conf->http_proxy) { + opkg_msg(DEBUG, "Setting environment variable: http_proxy = %s.\n", + conf->http_proxy); + setenv("http_proxy", conf->http_proxy, 1); + } + if (conf->ftp_proxy) { + opkg_msg(DEBUG, "Setting environment variable: ftp_proxy = %s.\n", + conf->ftp_proxy); + setenv("ftp_proxy", conf->ftp_proxy, 1); + } + if (conf->no_proxy) { + opkg_msg(DEBUG,"Setting environment variable: no_proxy = %s.\n", + conf->no_proxy); + setenv("no_proxy", conf->no_proxy, 1); + } + +#ifdef HAVE_CURL + CURLcode res; + FILE * file = fopen (tmp_file_location, "w"); + + curl = opkg_curl_init (cb, data); + if (curl) + { + curl_easy_setopt (curl, CURLOPT_URL, src); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, file); + + res = curl_easy_perform (curl); + fclose (file); + if (res) + { + long error_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &error_code); + opkg_msg(hide_error?DEBUG2:ERROR, "Failed to download %s: %s.\n", + src, curl_easy_strerror(res)); + free(tmp_file_location); + return -1; + } + + } + else + { + free(tmp_file_location); + return -1; + } +#else + { + int res; + const char *argv[8]; + int i = 0; + + argv[i++] = "wget"; + argv[i++] = "-q"; + if (conf->http_proxy || conf->ftp_proxy) { + argv[i++] = "-Y"; + argv[i++] = "on"; + } + argv[i++] = "-O"; + argv[i++] = tmp_file_location; + argv[i++] = src; + argv[i++] = NULL; + res = xsystem(argv); + + if (res) { + opkg_msg(ERROR, "Failed to download %s, wget returned %d.\n", src, res); + free(tmp_file_location); + return -1; + } + } +#endif + + err = file_move(tmp_file_location, dest_file_name); + + free(tmp_file_location); + + return err; +} + +static int +opkg_download_cache(const char *src, const char *dest_file_name, + curl_progress_func cb, void *data) +{ + char *cache_name = xstrdup(src); + char *cache_location, *p; + int err = 0; + + if (!conf->cache || str_starts_with(src, "file:")) { + err = opkg_download(src, dest_file_name, cb, data, 0); + goto out1; + } + + if(!file_is_dir(conf->cache)){ + opkg_msg(ERROR, "%s is not a directory.\n", + conf->cache); + err = 1; + goto out1; + } + + for (p = cache_name; *p; p++) + if (*p == '/') + *p = ','; /* looks nicer than | or # */ + + sprintf_alloc(&cache_location, "%s/%s", conf->cache, cache_name); + if (file_exists(cache_location)) + opkg_msg(NOTICE, "Copying %s.\n", cache_location); + else { + /* cache file with funky name not found, try simple name */ + free(cache_name); + char *filename = strrchr(dest_file_name,'/'); + if (filename) + cache_name = xstrdup(filename+1); // strip leading '/' + else + cache_name = xstrdup(dest_file_name); + free(cache_location); + sprintf_alloc(&cache_location, "%s/%s", conf->cache, cache_name); + if (file_exists(cache_location)) + opkg_msg(NOTICE, "Copying %s.\n", cache_location); + else { + err = opkg_download(src, cache_location, cb, data, 0); + if (err) { + (void) unlink(cache_location); + goto out2; + } + } + } + + err = file_copy(cache_location, dest_file_name); + + +out2: + free(cache_location); +out1: + free(cache_name); + return err; +} + +int +opkg_download_pkg(pkg_t *pkg, const char *dir) +{ + int err; + char *url; + char *stripped_filename; + + if (pkg->src == NULL) { + opkg_msg(ERROR, "Package %s is not available from any configured src.\n", + pkg->name); + return -1; + } + if (pkg->filename == NULL) { + opkg_msg(ERROR, "Package %s does not have a valid filename field.\n", + pkg->name); + return -1; + } + + sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename); + + /* The pkg->filename might be something like + "../../foo.opk". While this is correct, and exactly what we + want to use to construct url above, here we actually need to + use just the filename part, without any directory. */ + + stripped_filename = strrchr(pkg->filename, '/'); + if ( ! stripped_filename ) + stripped_filename = pkg->filename; + + sprintf_alloc(&pkg->local_filename, "%s/%s", dir, stripped_filename); + + err = opkg_download_cache(url, pkg->local_filename, NULL, NULL); + free(url); + + return err; +} + +/* + * Downloads file from url, installs in package database, return package name. + */ +int +opkg_prepare_url_for_install(const char *url, char **namep) +{ + int err = 0; + pkg_t *pkg; + + pkg = pkg_new(); + + if (str_starts_with(url, "http://") + || str_starts_with(url, "ftp://")) { + char *tmp_file; + char *file_basec = xstrdup(url); + char *file_base = basename(file_basec); + + sprintf_alloc(&tmp_file, "%s/%s", conf->tmp_dir, file_base); + err = opkg_download(url, tmp_file, NULL, NULL, 0); + if (err) + return err; + + err = pkg_init_from_file(pkg, tmp_file); + if (err) + return err; + + free(tmp_file); + free(file_basec); + + } else if (strcmp(&url[strlen(url) - 4], OPKG_PKG_EXTENSION) == 0 + || strcmp(&url[strlen(url) - 4], IPKG_PKG_EXTENSION) == 0 + || strcmp(&url[strlen(url) - 4], DPKG_PKG_EXTENSION) == 0) { + + err = pkg_init_from_file(pkg, url); + if (err) + return err; + opkg_msg(DEBUG2, "Package %s provided by hand (%s).\n", + pkg->name, pkg->local_filename); + pkg->provided_by_hand = 1; + + } else { + pkg_deinit(pkg); + free(pkg); + return 0; + } + + pkg->dest = conf->default_dest; + pkg->state_want = SW_INSTALL; + pkg->state_flag |= SF_PREFER; + hash_insert_pkg(pkg, 1); + + if (namep) { + *namep = pkg->name; + } + return 0; +} + +int +opkg_verify_file (char *text_file, char *sig_file) +{ +#if defined HAVE_GPGME + if (conf->check_signature == 0 ) + return 0; + int status = -1; + gpgme_ctx_t ctx; + gpgme_data_t sig, text, key; + gpgme_error_t err; + gpgme_verify_result_t result; + gpgme_signature_t s; + char *trusted_path = NULL; + + gpgme_check_version (NULL); + + err = gpgme_new (&ctx); + + if (err) + return -1; + + trusted_path = root_filename_alloc("/etc/opkg/trusted.gpg"); + err = gpgme_data_new_from_file (&key, trusted_path, 1); + free (trusted_path); + if (err) + { + return -1; + } + err = gpgme_op_import (ctx, key); + if (err) + { + gpgme_data_release (key); + return -1; + } + gpgme_data_release (key); + + err = gpgme_data_new_from_file (&sig, sig_file, 1); + if (err) + { + gpgme_release (ctx); + return -1; + } + + err = gpgme_data_new_from_file (&text, text_file, 1); + if (err) + { + gpgme_data_release (sig); + gpgme_release (ctx); + return -1; + } + + err = gpgme_op_verify (ctx, sig, text, NULL); + + result = gpgme_op_verify_result (ctx); + if (!result) + return -1; + + /* see if any of the signitures matched */ + s = result->signatures; + while (s) + { + status = gpg_err_code (s->status); + if (status == GPG_ERR_NO_ERROR) + break; + s = s->next; + } + + + gpgme_data_release (sig); + gpgme_data_release (text); + gpgme_release (ctx); + + return status; +#elif defined HAVE_OPENSSL + X509_STORE *store = NULL; + PKCS7 *p7 = NULL; + BIO *in = NULL, *indata = NULL; + + // Sig check failed by default ! + int status = -1; + + openssl_init(); + + // Set-up the key store + if(!(store = setup_verify(conf->signature_ca_file, conf->signature_ca_path))){ + opkg_msg(ERROR, "Can't open CA certificates.\n"); + goto verify_file_end; + } + + // Open a BIO to read the sig file + if (!(in = BIO_new_file(sig_file, "rb"))){ + opkg_msg(ERROR, "Can't open signature file %s.\n", sig_file); + goto verify_file_end; + } + + // Read the PKCS7 block contained in the sig file + p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); + if(!p7){ + opkg_msg(ERROR, "Can't read signature file %s (Corrupted ?).\n", + sig_file); + goto verify_file_end; + } +#if defined(HAVE_PATHFINDER) + if(conf->check_x509_path){ + if(!pkcs7_pathfinder_verify_signers(p7)){ + opkg_msg(ERROR, "pkcs7_pathfinder_verify_signers: " + "Path verification failed.\n"); + goto verify_file_end; + } + } +#endif + + // Open the Package file to authenticate + if (!(indata = BIO_new_file(text_file, "rb"))){ + opkg_msg(ERROR, "Can't open file %s.\n", text_file); + goto verify_file_end; + } + + // Let's verify the autenticity ! + if (PKCS7_verify(p7, NULL, store, indata, NULL, PKCS7_BINARY) != 1){ + // Get Off My Lawn! + opkg_msg(ERROR, "Verification failure.\n"); + }else{ + // Victory ! + status = 0; + } + +verify_file_end: + BIO_free(in); + BIO_free(indata); + PKCS7_free(p7); + X509_STORE_free(store); + + return status; +#else + /* mute `unused variable' warnings. */ + (void) sig_file; + (void) text_file; + (void) conf; + return 0; +#endif +} + + +#if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL) +static void openssl_init(void){ + static int init = 0; + + if(!init){ + OPENSSL_config(NULL); + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + init = 1; + } +} + +#endif + + +#if defined HAVE_OPENSSL +static X509_STORE * +setup_verify(char *CAfile, char *CApath) +{ + X509_STORE *store = NULL; + X509_LOOKUP *lookup = NULL; + + if(!(store = X509_STORE_new())){ + // Something bad is happening... + goto end; + } + + // adds the X509 file lookup method + lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file()); + if (lookup == NULL){ + goto end; + } + + // Autenticating against one CA file + if (CAfile) { + if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) { + // Invalid CA => Bye bye + opkg_msg(ERROR, "Error loading file %s.\n", CAfile); + goto end; + } + } else { + X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT); + } + + // Now look into CApath directory if supplied + lookup = X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir()); + if (lookup == NULL){ + goto end; + } + + if (CApath) { + if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) { + opkg_msg(ERROR, "Error loading directory %s.\n", CApath); + goto end; + } + } else { + X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT); + } + + // All right ! + ERR_clear_error(); + return store; + +end: + + X509_STORE_free(store); + return NULL; + +} + +#endif + +#ifdef HAVE_CURL +void opkg_curl_cleanup(void){ + if(curl != NULL){ + curl_easy_cleanup (curl); + curl = NULL; + } +} + +static CURL * +opkg_curl_init(curl_progress_func cb, void *data) +{ + + if(curl == NULL){ + curl = curl_easy_init(); + +#ifdef HAVE_SSLCURL + openssl_init(); + + if (conf->ssl_engine) { + + /* use crypto engine */ + if (curl_easy_setopt(curl, CURLOPT_SSLENGINE, conf->ssl_engine) != CURLE_OK){ + opkg_msg(ERROR, "Can't set crypto engine '%s'.\n", + conf->ssl_engine); + + opkg_curl_cleanup(); + return NULL; + } + /* set the crypto engine as default */ + if (curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L) != CURLE_OK){ + opkg_msg(ERROR, "Can't set crypto engine '%s' as default.\n", + conf->ssl_engine); + + opkg_curl_cleanup(); + return NULL; + } + } + + /* cert & key can only be in PEM case in the same file */ + if(conf->ssl_key_passwd){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, conf->ssl_key_passwd) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key password.\n"); + } + } + + /* sets the client certificate and its type */ + if(conf->ssl_cert_type){ + if (curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, conf->ssl_cert_type) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set certificate format.\n"); + } + } + /* SSL cert name isn't mandatory */ + if(conf->ssl_cert){ + curl_easy_setopt(curl, CURLOPT_SSLCERT, conf->ssl_cert); + } + + /* sets the client key and its type */ + if(conf->ssl_key_type){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, conf->ssl_key_type) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key format.\n"); + } + } + if(conf->ssl_key){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEY, conf->ssl_key) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key.\n"); + } + } + + /* Should we verify the peer certificate ? */ + if(conf->ssl_dont_verify_peer){ + /* + * CURLOPT_SSL_VERIFYPEER default is nonzero (curl => 7.10) + */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + }else{ +#ifdef HAVE_PATHFINDER + if(conf->check_x509_path){ + if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_ssl_ctx_function) != CURLE_OK){ + opkg_msg(DEBUG, "Failed to set ssl path verification callback.\n"); + }else{ + curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, NULL); + } + } +#endif + } + + /* certification authority file and/or path */ + if(conf->ssl_ca_file){ + curl_easy_setopt(curl, CURLOPT_CAINFO, conf->ssl_ca_file); + } + if(conf->ssl_ca_path){ + curl_easy_setopt(curl, CURLOPT_CAPATH, conf->ssl_ca_path); + } +#endif + + curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1); + if (conf->http_proxy || conf->ftp_proxy) + { + char *userpwd; + sprintf_alloc (&userpwd, "%s:%s", conf->proxy_user, + conf->proxy_passwd); + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, userpwd); + free (userpwd); + } + } + + curl_easy_setopt (curl, CURLOPT_NOPROGRESS, (cb == NULL)); + if (cb) + { + curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, data); + curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, cb); + } + + return curl; + +} +#endif diff --git a/src/libopkg/.svn/text-base/opkg_download.h.svn-base b/src/libopkg/.svn/text-base/opkg_download.h.svn-base new file mode 100644 index 0000000..91b990e --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_download.h.svn-base @@ -0,0 +1,39 @@ +/* opkg_download.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_DOWNLOAD_H +#define OPKG_DOWNLOAD_H + +#include "config.h" +#include "pkg.h" + +typedef void (*opkg_download_progress_callback)(int percent, char *url); +typedef int (*curl_progress_func)(void *data, double t, double d, double ultotal, double ulnow); + + +int opkg_download(const char *src, const char *dest_file_name, curl_progress_func cb, void *data, const short hide_error); +int opkg_download_pkg(pkg_t *pkg, const char *dir); +/* + * Downloads file from url, installs in package database, return package name. + */ +int opkg_prepare_url_for_install(const char *url, char **namep); + +int opkg_verify_file (char *text_file, char *sig_file); +#ifdef HAVE_CURL +void opkg_curl_cleanup(void); +#endif +#endif diff --git a/src/libopkg/.svn/text-base/opkg_install.c.svn-base b/src/libopkg/.svn/text-base/opkg_install.c.svn-base new file mode 100644 index 0000000..3925f58 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_install.c.svn-base @@ -0,0 +1,1528 @@ +/* opkg_install.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <unistd.h> +#include <sys/stat.h> + +#include "pkg.h" +#include "pkg_hash.h" +#include "pkg_extract.h" + +#include "opkg_install.h" +#include "opkg_configure.h" +#include "opkg_download.h" +#include "opkg_remove.h" + +#include "opkg_utils.h" +#include "opkg_message.h" +#include "opkg_cmd.h" +#include "opkg_defines.h" + +#include "sprintf_alloc.h" +#include "file_util.h" +#include "xsystem.h" +#include "libbb/libbb.h" + +static int +satisfy_dependencies_for(pkg_t *pkg) +{ + int i, err; + pkg_vec_t *depends = pkg_vec_alloc(); + pkg_t *dep; + char **tmp, **unresolved = NULL; + int ndepends; + + ndepends = pkg_hash_fetch_unsatisfied_dependencies(pkg, depends, + &unresolved); + + if (unresolved) { + opkg_msg(ERROR, "Cannot satisfy the following dependencies for %s:\n", + pkg->name); + tmp = unresolved; + while (*unresolved) { + opkg_message(ERROR, "\t%s", *unresolved); + free(*unresolved); + unresolved++; + } + free(tmp); + opkg_message(ERROR, "\n"); + if (! conf->force_depends) { + opkg_msg(INFO, + "This could mean that your package list is out of date or that the packages\n" + "mentioned above do not yet exist (try 'opkg update'). To proceed in spite\n" + "of this problem try again with the '-force-depends' option.\n"); + pkg_vec_free(depends); + return -1; + } + } + + if (ndepends <= 0) { + pkg_vec_free(depends); + return 0; + } + + /* Mark packages as to-be-installed */ + for (i=0; i < depends->len; i++) { + /* Dependencies should be installed the same place as pkg */ + if (depends->pkgs[i]->dest == NULL) { + depends->pkgs[i]->dest = pkg->dest; + } + depends->pkgs[i]->state_want = SW_INSTALL; + } + + for (i = 0; i < depends->len; i++) { + dep = depends->pkgs[i]; + /* The package was uninstalled when we started, but another + dep earlier in this loop may have depended on it and pulled + it in, so check first. */ + if ((dep->state_status != SS_INSTALLED) + && (dep->state_status != SS_UNPACKED)) { + opkg_msg(DEBUG2,"Calling opkg_install_pkg.\n"); + err = opkg_install_pkg(dep, 0); + /* mark this package as having been automatically installed to + * satisfy a dependancy */ + dep->auto_installed = 1; + if (err) { + pkg_vec_free(depends); + return err; + } + } + } + + pkg_vec_free(depends); + + return 0; +} + +static int +check_conflicts_for(pkg_t *pkg) +{ + int i; + pkg_vec_t *conflicts = NULL; + message_level_t level; + + if (conf->force_depends) { + level = NOTICE; + } else { + level = ERROR; + } + + if (!conf->force_depends) + conflicts = pkg_hash_fetch_conflicts(pkg); + + if (conflicts) { + opkg_msg(level, "The following packages conflict with %s:\n", + pkg->name); + i = 0; + while (i < conflicts->len) + opkg_msg(level, "\t%s", conflicts->pkgs[i++]->name); + opkg_message(level, "\n"); + pkg_vec_free(conflicts); + return -1; + } + return 0; +} + +static int +update_file_ownership(pkg_t *new_pkg, pkg_t *old_pkg) +{ + str_list_t *new_list, *old_list; + str_list_elt_t *iter, *niter; + + new_list = pkg_get_installed_files(new_pkg); + if (new_list == NULL) + return -1; + + for (iter = str_list_first(new_list), niter = str_list_next(new_list, iter); + iter; + iter = niter, niter = str_list_next(new_list, niter)) { + char *new_file = (char *)iter->data; + pkg_t *owner = file_hash_get_file_owner(new_file); + pkg_t *obs = hash_table_get(&conf->obs_file_hash, new_file); + + opkg_msg(DEBUG2, "%s: new_pkg=%s wants file %s, from owner=%s\n", + __func__, new_pkg->name, new_file, owner?owner->name:"<NULL>"); + + if (!owner || (owner == old_pkg) || obs) + file_hash_set_file_owner(new_file, new_pkg); + } + + if (old_pkg) { + old_list = pkg_get_installed_files(old_pkg); + if (old_list == NULL) { + pkg_free_installed_files(new_pkg); + return -1; + } + + for (iter = str_list_first(old_list), niter = str_list_next(old_list, iter); + iter; + iter = niter, niter = str_list_next(old_list, niter)) { + char *old_file = (char *)iter->data; + pkg_t *owner = file_hash_get_file_owner(old_file); + if (!owner || (owner == old_pkg)) { + /* obsolete */ + hash_table_insert(&conf->obs_file_hash, old_file, old_pkg); + } + } + pkg_free_installed_files(old_pkg); + } + pkg_free_installed_files(new_pkg); + return 0; +} + +static int +verify_pkg_installable(pkg_t *pkg) +{ + unsigned long kbs_available, pkg_size_kbs; + char *root_dir = NULL; + struct stat s; + + if (conf->force_space || pkg->installed_size == 0) + return 0; + + if (pkg->dest) + { + if (!strcmp(pkg->dest->name, "root") && conf->overlay_root + && !stat(conf->overlay_root, &s) && (s.st_mode & S_IFDIR)) + root_dir = conf->overlay_root; + else + root_dir = pkg->dest->root_dir; + } + + if (!root_dir) + root_dir = conf->default_dest->root_dir; + + kbs_available = get_available_kbytes(root_dir); + + pkg_size_kbs = (pkg->installed_size + 1023)/1024; + + if (pkg_size_kbs >= kbs_available) { + opkg_msg(ERROR, "Only have %ldkb available on filesystem %s, " + "pkg %s needs %ld\n", + kbs_available, root_dir, pkg->name, pkg_size_kbs); + return -1; + } + + return 0; +} + +static int +unpack_pkg_control_files(pkg_t *pkg) +{ + int err; + char *conffiles_file_name; + char *root_dir; + FILE *conffiles_file; + + sprintf_alloc(&pkg->tmp_unpack_dir, "%s/%s-XXXXXX", conf->tmp_dir, pkg->name); + + pkg->tmp_unpack_dir = mkdtemp(pkg->tmp_unpack_dir); + if (pkg->tmp_unpack_dir == NULL) { + opkg_perror(ERROR, "Failed to create temporary directory '%s'", + pkg->tmp_unpack_dir); + return -1; + } + + err = pkg_extract_control_files_to_dir(pkg, pkg->tmp_unpack_dir); + if (err) { + return err; + } + + /* XXX: CLEANUP: There might be a cleaner place to read in the + conffiles. Seems like I should be able to get everything to go + through pkg_init_from_file. If so, maybe it would make sense to + move all of unpack_pkg_control_files to that function. */ + + /* Don't need to re-read conffiles if we already have it */ + if (!nv_pair_list_empty(&pkg->conffiles)) { + return 0; + } + + sprintf_alloc(&conffiles_file_name, "%s/conffiles", pkg->tmp_unpack_dir); + if (! file_exists(conffiles_file_name)) { + free(conffiles_file_name); + return 0; + } + + conffiles_file = fopen(conffiles_file_name, "r"); + if (conffiles_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", conffiles_file_name); + free(conffiles_file_name); + return -1; + } + free(conffiles_file_name); + + while (1) { + char *cf_name; + char *cf_name_in_dest; + + cf_name = file_read_line_alloc(conffiles_file); + if (cf_name == NULL) { + break; + } + if (cf_name[0] == '\0') { + continue; + } + + /* Prepend dest->root_dir to conffile name. + Take pains to avoid multiple slashes. */ + root_dir = pkg->dest->root_dir; + if (conf->offline_root) + /* skip the offline_root prefix */ + root_dir = pkg->dest->root_dir + strlen(conf->offline_root); + sprintf_alloc(&cf_name_in_dest, "%s%s", root_dir, + cf_name[0] == '/' ? (cf_name + 1) : cf_name); + + /* Can't get an md5sum now, (file isn't extracted yet). + We'll wait until resolve_conffiles */ + conffile_list_append(&pkg->conffiles, cf_name_in_dest, NULL); + + free(cf_name); + free(cf_name_in_dest); + } + + fclose(conffiles_file); + + return 0; +} + +/* + * Remove packages which were auto_installed due to a dependency by old_pkg, + * which are no longer a dependency in the new (upgraded) pkg. + */ +static int +pkg_remove_orphan_dependent(pkg_t *pkg, pkg_t *old_pkg) +{ + int i, j, k, l, found,r, err = 0; + int n_deps; + pkg_t *p; + struct compound_depend *cd0, *cd1; + abstract_pkg_t **dependents; + + int count0 = old_pkg->pre_depends_count + + old_pkg->depends_count + + old_pkg->recommends_count + + old_pkg->suggests_count; + int count1 = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count0; i++) { + cd0 = &old_pkg->depends[i]; + if (cd0->type != DEPEND) + continue; + for (j=0; j<cd0->possibility_count; j++) { + + found = 0; + + for (k=0; k<count1; k++) { + cd1 = &pkg->depends[k]; + if (cd1->type != DEPEND) + continue; + for (l=0; l<cd1->possibility_count; l++) { + if (cd0->possibilities[j] + == cd1->possibilities[l]) { + found = 1; + break; + } + } + if (found) + break; + } + + if (found) + continue; + + /* + * old_pkg has a dependency that pkg does not. + */ + p = pkg_hash_fetch_installed_by_name( + cd0->possibilities[j]->pkg->name); + + if (!p) + continue; + + if (!p->auto_installed) + continue; + + n_deps = pkg_has_installed_dependents(p, &dependents); + n_deps--; /* don't count old_pkg */ + + if (n_deps == 0) { + opkg_msg(NOTICE, "%s was autoinstalled and is " + "now orphaned, removing.\n", + p->name); + + /* p has one installed dependency (old_pkg), + * which we need to ignore during removal. */ + p->state_flag |= SF_REPLACE; + + r = opkg_remove_pkg(p, 0); + if (!err) + err = r; + } else + opkg_msg(INFO, "%s was autoinstalled and is " + "still required by %d " + "installed packages.\n", + p->name, n_deps); + + } + } + + return err; +} + +/* returns number of installed replacees */ +static int +pkg_get_installed_replacees(pkg_t *pkg, pkg_vec_t *installed_replacees) +{ + abstract_pkg_t **replaces = pkg->replaces; + int replaces_count = pkg->replaces_count; + int i, j; + for (i = 0; i < replaces_count; i++) { + abstract_pkg_t *ab_pkg = replaces[i]; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + if (pkg_vec) { + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *replacee = pkg_vec->pkgs[j]; + if (!pkg_conflicts(pkg, replacee)) + continue; + if (replacee->state_status == SS_INSTALLED) { + pkg_vec_insert(installed_replacees, replacee); + } + } + } + } + return installed_replacees->len; +} + +static int +pkg_remove_installed_replacees(pkg_vec_t *replacees) +{ + int i; + int replaces_count = replacees->len; + for (i = 0; i < replaces_count; i++) { + pkg_t *replacee = replacees->pkgs[i]; + int err; + replacee->state_flag |= SF_REPLACE; /* flag it so remove won't complain */ + err = opkg_remove_pkg(replacee, 0); + if (err) + return err; + } + return 0; +} + +/* to unwind the removal: make sure they are installed */ +static int +pkg_remove_installed_replacees_unwind(pkg_vec_t *replacees) +{ + int i, err; + int replaces_count = replacees->len; + for (i = 0; i < replaces_count; i++) { + pkg_t *replacee = replacees->pkgs[i]; + if (replacee->state_status != SS_INSTALLED) { + opkg_msg(DEBUG2, "Calling opkg_install_pkg.\n"); + err = opkg_install_pkg(replacee, 0); + if (err) + return err; + } + } + return 0; +} + +/* compares versions of pkg and old_pkg, returns 0 if OK to proceed with installation of pkg, 1 otherwise */ +static int +opkg_install_check_downgrade(pkg_t *pkg, pkg_t *old_pkg, int message) +{ + if (old_pkg) { + char message_out[15]; + char *old_version = pkg_version_str_alloc(old_pkg); + char *new_version = pkg_version_str_alloc(pkg); + int cmp = pkg_compare_versions(old_pkg, pkg); + int rc = 0; + + memset(message_out,'\x0',15); + strncpy (message_out,"Upgrading ",strlen("Upgrading ")); + if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */ + cmp = -1 ; /* then we force opkg to downgrade */ + strncpy (message_out,"Downgrading ",strlen("Downgrading ")); /* We need to use a value < 0 because in the 0 case we are asking to */ + /* reinstall, and some check could fail asking the "force-reinstall" option */ + } + + if (cmp > 0) { + if(!conf->download_only) + opkg_msg(NOTICE, + "Not downgrading package %s on %s from %s to %s.\n", + old_pkg->name, old_pkg->dest->name, old_version, new_version); + rc = 1; + } else if (cmp < 0) { + if(!conf->download_only) + opkg_msg(NOTICE, "%s%s on %s from %s to %s...\n", + message_out, pkg->name, old_pkg->dest->name, old_version, new_version); + pkg->dest = old_pkg->dest; + rc = 0; + } else /* cmp == 0 */ { + if(!conf->download_only) + opkg_msg(NOTICE, "%s (%s) already install on %s.\n", + pkg->name, new_version, old_pkg->dest->name); + rc = 1; + } + free(old_version); + free(new_version); + return rc; + } else { + char message_out[15] ; + memset(message_out,'\x0',15); + if ( message ) + strncpy( message_out,"Upgrading ",strlen("Upgrading ") ); + else + strncpy( message_out,"Installing ",strlen("Installing ") ); + char *version = pkg_version_str_alloc(pkg); + + if(!conf->download_only) + opkg_msg(NOTICE, "%s%s (%s) to %s...\n", message_out, + pkg->name, version, pkg->dest->name); + free(version); + } + return 0; +} + + +static int +prerm_upgrade_old_pkg(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + + 1. If a version of the package is already installed, call + old-prerm upgrade new-version + 2. If the script runs but exits with a non-zero exit status + new-prerm failed-upgrade old-version + Error unwind, for both the above cases: + old-postinst abort-upgrade new-version + */ + return 0; +} + +static int +prerm_upgrade_old_pkg_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + (See prerm_upgrade_old_package for details) + */ + return 0; +} + +static int +prerm_deconfigure_conflictors(pkg_t *pkg, pkg_vec_t *conflictors) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + 2. If a 'conflicting' package is being removed at the same time: + 1. If any packages depended on that conflicting package and + --auto-deconfigure is specified, call, for each such package: + deconfigured's-prerm deconfigure \ + in-favour package-being-installed version \ + removing conflicting-package version + Error unwind: + deconfigured's-postinst abort-deconfigure \ + in-favour package-being-installed-but-failed version \ + removing conflicting-package version + + The deconfigured packages are marked as requiring + configuration, so that if --install is used they will be + configured again if possible. + 2. To prepare for removal of the conflicting package, call: + conflictor's-prerm remove in-favour package new-version + Error unwind: + conflictor's-postinst abort-remove in-favour package new-version + */ + return 0; +} + +static int +prerm_deconfigure_conflictors_unwind(pkg_t *pkg, pkg_vec_t *conflictors) +{ + /* DPKG_INCOMPATIBILITY: dpkg does some things here that we don't + do yet. Do we care? (See prerm_deconfigure_conflictors for + details) */ + return 0; +} + +static int +preinst_configure(pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + char *preinst_args; + + if (old_pkg) { + char *old_version = pkg_version_str_alloc(old_pkg); + sprintf_alloc(&preinst_args, "upgrade %s", old_version); + free(old_version); + } else if (pkg->state_status == SS_CONFIG_FILES) { + char *pkg_version = pkg_version_str_alloc(pkg); + sprintf_alloc(&preinst_args, "install %s", pkg_version); + free(pkg_version); + } else { + preinst_args = xstrdup("install"); + } + + err = pkg_run_script(pkg, "preinst", preinst_args); + if (err) { + opkg_msg(ERROR, "Aborting installation of %s.\n", pkg->name); + return -1; + } + + free(preinst_args); + + return 0; +} + +static int +preinst_configure_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does the following error unwind, should we? + pkg->postrm abort-upgrade old-version + OR pkg->postrm abort-install old-version + OR pkg->postrm abort-install + */ + return 0; +} + +static char * +backup_filename_alloc(const char *file_name) +{ + char *backup; + + sprintf_alloc(&backup, "%s%s", file_name, OPKG_BACKUP_SUFFIX); + + return backup; +} + + +static int +backup_make_backup(const char *file_name) +{ + int err; + char *backup; + + backup = backup_filename_alloc(file_name); + err = file_copy(file_name, backup); + if (err) { + opkg_msg(ERROR, "Failed to copy %s to %s\n", + file_name, backup); + } + + free(backup); + + return err; +} + +static int +backup_exists_for(const char *file_name) +{ + int ret; + char *backup; + + backup = backup_filename_alloc(file_name); + + ret = file_exists(backup); + + free(backup); + + return ret; +} + +static int +backup_remove(const char *file_name) +{ + char *backup; + + backup = backup_filename_alloc(file_name); + unlink(backup); + free(backup); + + return 0; +} + +static int +backup_modified_conffiles(pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + conffile_list_elt_t *iter; + conffile_t *cf; + + if (conf->noaction) return 0; + + /* Backup all modified conffiles */ + if (old_pkg) { + for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { + char *cf_name; + + cf = iter->data; + cf_name = root_filename_alloc(cf->name); + + /* Don't worry if the conffile is just plain gone */ + if (file_exists(cf_name) && conffile_has_been_modified(cf)) { + err = backup_make_backup(cf_name); + if (err) { + return err; + } + } + free(cf_name); + } + } + + /* Backup all conffiles that were not conffiles in old_pkg */ + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + char *cf_name; + cf = (conffile_t *)iter->data; + cf_name = root_filename_alloc(cf->name); + /* Ignore if this was a conffile in old_pkg as well */ + if (pkg_get_conffile(old_pkg, cf->name)) { + continue; + } + + if (file_exists(cf_name) && (! backup_exists_for(cf_name))) { + err = backup_make_backup(cf_name); + if (err) { + return err; + } + } + free(cf_name); + } + + return 0; +} + +static int +backup_modified_conffiles_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + conffile_list_elt_t *iter; + + if (old_pkg) { + for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { + backup_remove(((nv_pair_t *)iter->data)->name); + } + } + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + backup_remove(((nv_pair_t *)iter->data)->name); + } + + return 0; +} + + +static int +check_data_file_clashes(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + opkg takes a slightly different approach than dpkg at this + point. dpkg installs each file in the new package while + creating a backup for any file that is replaced, (so that it + can unwind if necessary). To avoid complexity and redundant + storage, opkg doesn't do any installation until later, (at the + point at which dpkg removes the backups. + + But, we do have to check for data file clashes, since after + installing a package with a file clash, removing either of the + packages involved in the clash has the potential to break the + other package. + */ + str_list_t *files_list; + str_list_elt_t *iter, *niter; + char *filename; + int clashes = 0; + + files_list = pkg_get_installed_files(pkg); + if (files_list == NULL) + return -1; + + for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); + iter; + iter = niter, niter = str_list_next(files_list, iter)) { + filename = (char *) iter->data; + if (file_exists(filename) && (! file_is_dir(filename))) { + pkg_t *owner; + pkg_t *obs; + + if (backup_exists_for(filename)) { + continue; + } + + /* Pre-existing files are OK if force-overwrite was asserted. */ + if (conf->force_overwrite) { + /* but we need to change who owns this file */ + file_hash_set_file_owner(filename, pkg); + continue; + } + + owner = file_hash_get_file_owner(filename); + + /* Pre-existing files are OK if owned by the pkg being upgraded. */ + if (owner && old_pkg) { + if (strcmp(owner->name, old_pkg->name) == 0) { + continue; + } + } + + /* Pre-existing files are OK if owned by a package replaced by new pkg. */ + if (owner) { + opkg_msg(DEBUG2, "Checking replaces for %s in package %s\n", + filename, owner->name); + if (pkg_replaces(pkg, owner)) { + continue; + } +/* If the file that would be installed is owned by the same package, ( as per a reinstall or similar ) + then it's ok to overwrite. */ + if (strcmp(owner->name,pkg->name)==0){ + opkg_msg(INFO, "Replacing pre-existing file %s" + " owned by package %s\n", + filename, owner->name); + continue; + } + } + + /* Pre-existing files are OK if they are obsolete */ + obs = hash_table_get(&conf->obs_file_hash, filename); + if (obs) { + opkg_msg(INFO, "Pre-exiting file %s is obsolete." + " obs_pkg=%s\n", + filename, obs->name); + continue; + } + + /* We have found a clash. */ + opkg_msg(ERROR, "Package %s wants to install file %s\n" + "\tBut that file is already provided by package ", + pkg->name, filename); + if (owner) { + opkg_message(ERROR, "%s\n", owner->name); + } else { + opkg_message(ERROR, "<no package>\n" + "Please move this file out of the way and try again.\n"); + } + clashes++; + } + } + pkg_free_installed_files(pkg); + + return clashes; +} + +/* + * XXX: This function sucks, as does the below comment. + */ +static int +check_data_file_clashes_change(pkg_t *pkg, pkg_t *old_pkg) +{ + /* Basically that's the worst hack I could do to be able to change ownership of + file list, but, being that we have no way to unwind the mods, due to structure + of hash table, probably is the quickest hack too, whishing it would not slow-up thing too much. + What we do here is change the ownership of file in hash if a replace ( or similar events + happens ) + Only the action that are needed to change name should be considered. + @@@ To change after 1.0 release. + */ + str_list_t *files_list; + str_list_elt_t *iter, *niter; + + char *root_filename = NULL; + + files_list = pkg_get_installed_files(pkg); + if (files_list == NULL) + return -1; + + for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); + iter; + iter = niter, niter = str_list_next(files_list, niter)) { + char *filename = (char *) iter->data; + if (root_filename) { + free(root_filename); + root_filename = NULL; + } + root_filename = root_filename_alloc(filename); + if (file_exists(root_filename) && (! file_is_dir(root_filename))) { + pkg_t *owner; + + owner = file_hash_get_file_owner(filename); + + if (conf->force_overwrite) { + /* but we need to change who owns this file */ + file_hash_set_file_owner(filename, pkg); + continue; + } + + + /* Pre-existing files are OK if owned by a package replaced by new pkg. */ + if (owner) { + if (pkg_replaces(pkg, owner)) { +/* It's now time to change the owner of that file. + It has been "replaced" from the new "Replaces", then I need to inform lists file about that. */ + opkg_msg(INFO, "Replacing pre-existing file %s " + "owned by package %s\n", + filename, owner->name); + file_hash_set_file_owner(filename, pkg); + continue; + } + } + + } + } + if (root_filename) { + free(root_filename); + root_filename = NULL; + } + pkg_free_installed_files(pkg); + + return 0; +} + +static int +check_data_file_clashes_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* Nothing to do since check_data_file_clashes doesn't change state */ + return 0; +} + +static int +postrm_upgrade_old_pkg(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: dpkg does the following here, should we? + 1. If the package is being upgraded, call + old-postrm upgrade new-version + 2. If this fails, attempt: + new-postrm failed-upgrade old-version + Error unwind, for both cases: + old-preinst abort-upgrade new-version */ + return 0; +} + +static int +postrm_upgrade_old_pkg_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + (See postrm_upgrade_old_pkg for details) + */ + return 0; +} + +static int +remove_obsolesced_files(pkg_t *pkg, pkg_t *old_pkg) +{ + int err = 0; + str_list_t *old_files; + str_list_elt_t *of; + str_list_t *new_files; + str_list_elt_t *nf; + hash_table_t new_files_table; + + old_files = pkg_get_installed_files(old_pkg); + if (old_files == NULL) + return -1; + + new_files = pkg_get_installed_files(pkg); + if (new_files == NULL) { + pkg_free_installed_files(old_pkg); + return -1; + } + + new_files_table.entries = NULL; + hash_table_init("new_files" , &new_files_table, 20); + for (nf = str_list_first(new_files); nf; nf = str_list_next(new_files, nf)) { + if (nf && nf->data) + hash_table_insert(&new_files_table, nf->data, nf->data); + } + + for (of = str_list_first(old_files); of; of = str_list_next(old_files, of)) { + pkg_t *owner; + char *old, *new; + old = (char *)of->data; + new = (char *) hash_table_get (&new_files_table, old); + if (new) + continue; + + if (file_is_dir(old)) { + continue; + } + owner = file_hash_get_file_owner(old); + if (owner != old_pkg) { + /* in case obsolete file no longer belongs to old_pkg */ + continue; + } + + /* old file is obsolete */ + opkg_msg(NOTICE, "Removing obsolete file %s.\n", old); + if (!conf->noaction) { + err = unlink(old); + if (err) { + opkg_perror(ERROR, "unlinking %s failed", old); + } + } + } + + hash_table_deinit(&new_files_table); + pkg_free_installed_files(old_pkg); + pkg_free_installed_files(pkg); + + return err; +} + +static int +install_maintainer_scripts(pkg_t *pkg, pkg_t *old_pkg) +{ + int ret; + char *prefix; + + sprintf_alloc(&prefix, "%s.", pkg->name); + ret = pkg_extract_control_files_to_dir_with_prefix(pkg, + pkg->dest->info_dir, + prefix); + free(prefix); + return ret; +} + +static int +remove_disappeared(pkg_t *pkg) +{ + /* DPKG_INCOMPATIBILITY: + This is a fairly sophisticated dpkg operation. Shall we + skip it? */ + + /* Any packages all of whose files have been overwritten during the + installation, and which aren't required for dependencies, are + considered to have been removed. For each such package + 1. disappearer's-postrm disappear overwriter overwriter-version + 2. The package's maintainer scripts are removed + 3. It is noted in the status database as being in a sane state, + namely not installed (any conffiles it may have are ignored, + rather than being removed by dpkg). Note that disappearing + packages do not have their prerm called, because dpkg doesn't + know in advance that the package is going to vanish. + */ + return 0; +} + +static int +install_data_files(pkg_t *pkg) +{ + int err; + + /* opkg takes a slightly different approach to data file backups + than dpkg. Rather than removing backups at this point, we + actually do the data file installation now. See comments in + check_data_file_clashes() for more details. */ + + opkg_msg(INFO, "Extracting data files to %s.\n", pkg->dest->root_dir); + err = pkg_extract_data_files_to_dir(pkg, pkg->dest->root_dir); + if (err) { + return err; + } + + /* The "Essential" control field may only be present in the control + * file and not in the Packages list. Ensure we capture it regardless. + * + * XXX: This should be fixed outside of opkg, in the Package list. + */ + set_flags_from_control(pkg) ; + + opkg_msg(DEBUG, "Calling pkg_write_filelist.\n"); + err = pkg_write_filelist(pkg); + if (err) + return err; + + /* XXX: FEATURE: opkg should identify any files which existed + before installation and which were overwritten, (see + check_data_file_clashes()). What it must do is remove any such + files from the filelist of the old package which provided the + file. Otherwise, if the old package were removed at some point + it would break the new package. Removing the new package will + also break the old one, but this cannot be helped since the old + package's file has already been deleted. This is the importance + of check_data_file_clashes(), and only allowing opkg to install + a clashing package with a user force. */ + + return 0; +} + +static int +resolve_conffiles(pkg_t *pkg) +{ + conffile_list_elt_t *iter; + conffile_t *cf; + char *cf_backup; + char *md5sum; + + if (conf->noaction) return 0; + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + char *root_filename; + cf = (conffile_t *)iter->data; + root_filename = root_filename_alloc(cf->name); + + /* Might need to initialize the md5sum for each conffile */ + if (cf->value == NULL) { + cf->value = file_md5sum_alloc(root_filename); + } + + if (!file_exists(root_filename)) { + free(root_filename); + continue; + } + + cf_backup = backup_filename_alloc(root_filename); + + if (file_exists(cf_backup)) { + /* Let's compute md5 to test if files are changed */ + md5sum = file_md5sum_alloc(cf_backup); + if (md5sum && cf->value && strcmp(cf->value,md5sum) != 0 ) { + if (conf->force_maintainer) { + opkg_msg(NOTICE, "Conffile %s using maintainer's setting.\n", + cf_backup); + } else { + char *new_conffile; + sprintf_alloc(&new_conffile, "%s-opkg", root_filename); + opkg_msg(ERROR, "Existing conffile %s " + "is different from the conffile in the new package." + " The new conffile will be placed at %s.\n", + root_filename, new_conffile); + rename(root_filename, new_conffile); + rename(cf_backup, root_filename); + free(new_conffile); + } + } + unlink(cf_backup); + if (md5sum) + free(md5sum); + } + + free(cf_backup); + free(root_filename); + } + + return 0; +} + + +int +opkg_install_by_name(const char *pkg_name) +{ + int cmp; + pkg_t *old, *new; + char *old_version, *new_version; + + old = pkg_hash_fetch_installed_by_name(pkg_name); + if (old) + opkg_msg(DEBUG2, "Old versions from pkg_hash_fetch %s.\n", + old->version); + + new = pkg_hash_fetch_best_installation_candidate_by_name(pkg_name); + if (new == NULL) { + opkg_msg(NOTICE, "Unknown package '%s'.\n", pkg_name); + return -1; + } + + opkg_msg(DEBUG2, "Versions from pkg_hash_fetch:"); + if ( old ) + opkg_message(DEBUG2, " old %s ", old->version); + opkg_message(DEBUG2, " new %s\n", new->version); + + new->state_flag |= SF_USER; + if (old) { + old_version = pkg_version_str_alloc(old); + new_version = pkg_version_str_alloc(new); + + cmp = pkg_compare_versions(old, new); + if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */ + opkg_msg(DEBUG, "Forcing downgrade\n"); + cmp = -1 ; /* then we force opkg to downgrade */ + /* We need to use a value < 0 because in the 0 case we are asking to */ + /* reinstall, and some check could fail asking the "force-reinstall" option */ + } + opkg_msg(DEBUG, "Comparing visible versions of pkg %s:" + "\n\t%s is installed " + "\n\t%s is available " + "\n\t%d was comparison result\n", + pkg_name, old_version, new_version, cmp); + if (cmp == 0) { + opkg_msg(NOTICE, + "Package %s (%s) installed in %s is up to date.\n", + old->name, old_version, old->dest->name); + free(old_version); + free(new_version); + return 0; + } else if (cmp > 0) { + opkg_msg(NOTICE, + "Not downgrading package %s on %s from %s to %s.\n", + old->name, old->dest->name, old_version, new_version); + free(old_version); + free(new_version); + return 0; + } else if (cmp < 0) { + new->dest = old->dest; + old->state_want = SW_DEINSTALL; + } + free(old_version); + free(new_version); + } + + opkg_msg(DEBUG2,"Calling opkg_install_pkg.\n"); + return opkg_install_pkg(new, 0); +} + +/** + * @brief Really install a pkg_t + */ +int +opkg_install_pkg(pkg_t *pkg, int from_upgrade) +{ + int err = 0; + int message = 0; + pkg_t *old_pkg = NULL; + pkg_vec_t *replacees; + abstract_pkg_t *ab_pkg = NULL; + int old_state_flag; + char* file_md5; +#ifdef HAVE_SHA256 + char* file_sha256; +#endif + sigset_t newset, oldset; + + if ( from_upgrade ) + message = 1; /* Coming from an upgrade, and should change the output message */ + + opkg_msg(DEBUG2, "Calling pkg_arch_supported.\n"); + + if (!pkg_arch_supported(pkg)) { + opkg_msg(ERROR, "INTERNAL ERROR: architecture %s for pkg %s is unsupported.\n", + pkg->architecture, pkg->name); + return -1; + } + if (pkg->state_status == SS_INSTALLED && conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + + opkg_msg(NOTICE, "Package %s is already installed on %s.\n", + pkg->name, pkg->dest->name); + return 0; + } + + if (pkg->dest == NULL) { + pkg->dest = conf->default_dest; + } + + old_pkg = pkg_hash_fetch_installed_by_name(pkg->name); + + err = opkg_install_check_downgrade(pkg, old_pkg, message); + if (err) + return -1; + + pkg->state_want = SW_INSTALL; + if (old_pkg){ + old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependencies */ + } + + err = check_conflicts_for(pkg); + if (err) + return -1; + + /* this setup is to remove the upgrade scenario in the end when + installing pkg A, A deps B & B deps on A. So both B and A are + installed. Then A's installation is started resulting in an + uncecessary upgrade */ + if (pkg->state_status == SS_INSTALLED) + return 0; + + err = verify_pkg_installable(pkg); + if (err) + return -1; + + if (pkg->local_filename == NULL) { + if(!conf->cache && conf->download_only){ + char cwd[4096]; + if(getcwd(cwd, sizeof(cwd)) != NULL) + err = opkg_download_pkg(pkg, cwd); + else + return -1; + } else { + err = opkg_download_pkg(pkg, conf->tmp_dir); + } + if (err) { + opkg_msg(ERROR, "Failed to download %s. " + "Perhaps you need to run 'opkg update'?\n", + pkg->name); + return -1; + } + } + + /* check that the repository is valid */ + #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + char *list_file_name, *sig_file_name, *lists_dir; + + /* check to ensure the package has come from a repository */ + if (conf->check_signature && pkg->src) + { + sprintf_alloc (&lists_dir, "%s", + (conf->restrict_to_default_dest) + ? conf->default_dest->lists_dir + : conf->lists_dir); + sprintf_alloc (&list_file_name, "%s/%s", lists_dir, pkg->src->name); + sprintf_alloc (&sig_file_name, "%s/%s.sig", lists_dir, pkg->src->name); + + if (file_exists (sig_file_name)) + { + if (opkg_verify_file (list_file_name, sig_file_name)){ + opkg_msg(ERROR, "Failed to verify the signature of %s.\n", + list_file_name); + return -1; + } + }else{ + opkg_msg(ERROR, "Signature file is missing for %s. " + "Perhaps you need to run 'opkg update'?\n", + pkg->name); + return -1; + } + + free (lists_dir); + free (list_file_name); + free (sig_file_name); + } + #endif + + /* Check for md5 values */ + if (pkg->md5sum) + { + file_md5 = file_md5sum_alloc(pkg->local_filename); + if (file_md5 && strcmp(file_md5, pkg->md5sum)) + { + opkg_msg(ERROR, "Package %s md5sum mismatch. " + "Either the opkg or the package index are corrupt. " + "Try 'opkg update'.\n", + pkg->name); + free(file_md5); + return -1; + } + if (file_md5) + free(file_md5); + } + +#ifdef HAVE_SHA256 + /* Check for sha256 value */ + if(pkg->sha256sum) + { + file_sha256 = file_sha256sum_alloc(pkg->local_filename); + if (file_sha256 && strcmp(file_sha256, pkg->sha256sum)) + { + opkg_msg(ERROR, "Package %s sha256sum mismatch. " + "Either the opkg or the package index are corrupt. " + "Try 'opkg update'.\n", + pkg->name); + free(file_sha256); + return -1; + } + if (file_sha256) + free(file_sha256); + } +#endif + if(conf->download_only) { + if (conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + } + return 0; + } + + if (pkg->tmp_unpack_dir == NULL) { + if (unpack_pkg_control_files(pkg) == -1) { + opkg_msg(ERROR, "Failed to unpack control files from %s.\n", + pkg->local_filename); + return -1; + } + } + + err = update_file_ownership(pkg, old_pkg); + if (err) + return -1; + + if (conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + if (pkg->state_status == SS_UNPACKED) + /* Circular dependency has installed it for us. */ + return 0; + } + + replacees = pkg_vec_alloc(); + pkg_get_installed_replacees(pkg, replacees); + + /* this next section we do with SIGINT blocked to prevent inconsistency between opkg database and filesystem */ + + sigemptyset(&newset); + sigaddset(&newset, SIGINT); + sigprocmask(SIG_BLOCK, &newset, &oldset); + + opkg_state_changed++; + pkg->state_flag |= SF_FILELIST_CHANGED; + + if (old_pkg) + pkg_remove_orphan_dependent(pkg, old_pkg); + + /* XXX: BUG: we really should treat replacement more like an upgrade + * Instead, we're going to remove the replacees + */ + err = pkg_remove_installed_replacees(replacees); + if (err) + goto UNWIND_REMOVE_INSTALLED_REPLACEES; + + err = prerm_upgrade_old_pkg(pkg, old_pkg); + if (err) + goto UNWIND_PRERM_UPGRADE_OLD_PKG; + + err = prerm_deconfigure_conflictors(pkg, replacees); + if (err) + goto UNWIND_PRERM_DECONFIGURE_CONFLICTORS; + + err = preinst_configure(pkg, old_pkg); + if (err) + goto UNWIND_PREINST_CONFIGURE; + + err = backup_modified_conffiles(pkg, old_pkg); + if (err) + goto UNWIND_BACKUP_MODIFIED_CONFFILES; + + err = check_data_file_clashes(pkg, old_pkg); + if (err) + goto UNWIND_CHECK_DATA_FILE_CLASHES; + + err = postrm_upgrade_old_pkg(pkg, old_pkg); + if (err) + goto UNWIND_POSTRM_UPGRADE_OLD_PKG; + + if (conf->noaction) + return 0; + + /* point of no return: no unwinding after this */ + if (old_pkg) { + old_pkg->state_want = SW_DEINSTALL; + + if (old_pkg->state_flag & SF_NOPRUNE) { + opkg_msg(INFO, "Not removing obsolesced files because " + "package %s marked noprune.\n", + old_pkg->name); + } else { + opkg_msg(INFO, "Removing obsolesced files for %s\n", + old_pkg->name); + if (remove_obsolesced_files(pkg, old_pkg)) { + opkg_msg(ERROR, "Failed to determine " + "obsolete files from previously " + "installed %s\n", old_pkg->name); + } + } + + /* removing files from old package, to avoid ghost files */ + remove_data_files_and_list(old_pkg); + remove_maintainer_scripts(old_pkg); + + /* maintain the "Auto-Installed: yes" flag */ + pkg->auto_installed = old_pkg->auto_installed; + } + + + opkg_msg(INFO, "Installing maintainer scripts.\n"); + if (install_maintainer_scripts(pkg, old_pkg)) { + opkg_msg(ERROR, "Failed to extract maintainer scripts for %s." + " Package debris may remain!\n", + pkg->name); + goto pkg_is_hosed; + } + + /* the following just returns 0 */ + remove_disappeared(pkg); + + opkg_msg(INFO, "Installing data files for %s.\n", pkg->name); + + if (install_data_files(pkg)) { + opkg_msg(ERROR, "Failed to extract data files for %s. " + "Package debris may remain!\n", + pkg->name); + goto pkg_is_hosed; + } + + err = check_data_file_clashes_change(pkg, old_pkg); + if (err) { + opkg_msg(ERROR, "check_data_file_clashes_change() failed for " + "for files belonging to %s.\n", + pkg->name); + } + + opkg_msg(INFO, "Resolving conf files for %s\n", pkg->name); + resolve_conffiles(pkg); + + pkg->state_status = SS_UNPACKED; + old_state_flag = pkg->state_flag; + pkg->state_flag &= ~SF_PREFER; + opkg_msg(DEBUG, "pkg=%s old_state_flag=%x state_flag=%x\n", + pkg->name, old_state_flag, pkg->state_flag); + + if (old_pkg) + old_pkg->state_status = SS_NOT_INSTALLED; + + time(&pkg->installed_time); + + ab_pkg = pkg->parent; + if (ab_pkg) + ab_pkg->state_status = pkg->state_status; + + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + pkg_vec_free (replacees); + return 0; + + + UNWIND_POSTRM_UPGRADE_OLD_PKG: + postrm_upgrade_old_pkg_unwind(pkg, old_pkg); + UNWIND_CHECK_DATA_FILE_CLASHES: + check_data_file_clashes_unwind(pkg, old_pkg); + UNWIND_BACKUP_MODIFIED_CONFFILES: + backup_modified_conffiles_unwind(pkg, old_pkg); + UNWIND_PREINST_CONFIGURE: + preinst_configure_unwind(pkg, old_pkg); + UNWIND_PRERM_DECONFIGURE_CONFLICTORS: + prerm_deconfigure_conflictors_unwind(pkg, replacees); + UNWIND_PRERM_UPGRADE_OLD_PKG: + prerm_upgrade_old_pkg_unwind(pkg, old_pkg); + UNWIND_REMOVE_INSTALLED_REPLACEES: + pkg_remove_installed_replacees_unwind(replacees); + +pkg_is_hosed: + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + + pkg_vec_free (replacees); + return -1; +} diff --git a/src/libopkg/.svn/text-base/opkg_install.h.svn-base b/src/libopkg/.svn/text-base/opkg_install.h.svn-base new file mode 100644 index 0000000..eaffff8 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_install.h.svn-base @@ -0,0 +1,27 @@ +/* opkg_install.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_INSTALL_H +#define OPKG_INSTALL_H + +#include "pkg.h" +#include "opkg_conf.h" + +int opkg_install_by_name(const char *pkg_name); +int opkg_install_pkg(pkg_t *pkg, int from_upgrading); + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_message.c.svn-base b/src/libopkg/.svn/text-base/opkg_message.c.svn-base new file mode 100644 index 0000000..7114e3a --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_message.c.svn-base @@ -0,0 +1,121 @@ +/* opkg_message.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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, 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. +*/ + +#include <stdio.h> + +#include "opkg_conf.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + +struct errlist { + char *errmsg; + struct errlist *next; +}; + +static struct errlist *error_list_head, *error_list_tail; + +static void +push_error_list(char *msg) +{ + struct errlist *e; + + e = xcalloc(1, sizeof(struct errlist)); + e->errmsg = xstrdup(msg); + e->next = NULL; + + if (error_list_head) { + error_list_tail->next = e; + error_list_tail = e; + } else { + error_list_head = error_list_tail = e; + } +} + +void +free_error_list(void) +{ + struct errlist *err, *err_tmp; + + err = error_list_head; + while (err != NULL) { + free(err->errmsg); + err_tmp = err; + err = err->next; + free(err_tmp); + } +} + +void +print_error_list(void) +{ + struct errlist *err = error_list_head; + + if (err) { + printf("Collected errors:\n"); + /* Here we print the errors collected and free the list */ + while (err != NULL) { + printf(" * %s", err->errmsg); + err = err->next; + } + } +} + +void +opkg_message (message_level_t level, const char *fmt, ...) +{ + va_list ap; + + if (conf->verbosity < level) + return; + + if (conf->opkg_vmessage) { + /* Pass the message to libopkg users. */ + va_start (ap, fmt); + conf->opkg_vmessage(level, fmt, ap); + va_end (ap); + return; + } + + va_start (ap, fmt); + + if (level == ERROR) { +#define MSG_LEN 4096 + char msg[MSG_LEN]; + int ret; + ret = vsnprintf(msg, MSG_LEN, fmt, ap); + if (ret < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vsnprintf.\n", + __FUNCTION__); + va_end (ap); + exit(EXIT_FAILURE); + } + if (ret >= MSG_LEN) { + fprintf(stderr, "%s: Message truncated.\n", + __FUNCTION__); + } + push_error_list(msg); + } else { + if (vprintf(fmt, ap) < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vprintf.\n", + __FUNCTION__); + exit(EXIT_FAILURE); + } + } + + va_end (ap); +} diff --git a/src/libopkg/.svn/text-base/opkg_message.h.svn-base b/src/libopkg/.svn/text-base/opkg_message.h.svn-base new file mode 100644 index 0000000..4fa2a0b --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_message.h.svn-base @@ -0,0 +1,47 @@ +/* opkg_message.h - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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, 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. +*/ + +#ifndef _OPKG_MESSAGE_H_ +#define _OPKG_MESSAGE_H_ + +#include <string.h> +#include <errno.h> + +typedef enum { + ERROR, /* error conditions */ + NOTICE, /* normal but significant condition */ + INFO, /* informational message */ + DEBUG, /* debug level message */ + DEBUG2, /* more debug level message */ +} message_level_t; + +void free_error_list(void); +void print_error_list(void); +void opkg_message(message_level_t level, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +#define opkg_msg(l, fmt, args...) \ + do { \ + if (l == NOTICE) \ + opkg_message(l, fmt, ##args); \ + else \ + opkg_message(l, "%s: "fmt, __FUNCTION__, ##args); \ + } while (0) + +#define opkg_perror(l, fmt, args...) \ + opkg_msg(l, fmt": %s.\n", ##args, strerror(errno)) + +#endif /* _OPKG_MESSAGE_H_ */ diff --git a/src/libopkg/.svn/text-base/opkg_pathfinder.c.svn-base b/src/libopkg/.svn/text-base/opkg_pathfinder.c.svn-base new file mode 100644 index 0000000..bf7dab6 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_pathfinder.c.svn-base @@ -0,0 +1,100 @@ +/* vi: set noexpandtab sw=4 sts=4: */ +/* opkg_pathfinder.c - the opkg package management system + + Copyright (C) 2009 Camille Moncelier <moncelier@devlife.org> + + 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, 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. +*/ +#include "config.h" + +#include <openssl/ssl.h> +#include <libpathfinder.h> +#include <stdlib.h> +#if defined(HAVE_SSLCURL) +#include <curl/curl.h> +#endif + +#include "libbb/libbb.h" +#include "opkg_message.h" + +#if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL) +/* + * This callback is called instead of X509_verify_cert to perform path + * validation on a certificate using pathfinder. + * + */ +static int pathfinder_verify_callback(X509_STORE_CTX *ctx, void *arg) +{ + char *errmsg; + const char *hex = "0123456789ABCDEF"; + size_t size = i2d_X509(ctx->cert, NULL); + unsigned char *keybuf, *iend; + iend = keybuf = xmalloc(size); + i2d_X509(ctx->cert, &iend); + char *certdata_str = xmalloc(size * 2 + 1); + unsigned char *cp = keybuf; + char *certdata_str_i = certdata_str; + while (cp < iend) + { + unsigned char ch = *cp++; + *certdata_str_i++ = hex[(ch >> 4) & 0xf]; + *certdata_str_i++ = hex[ch & 0xf]; + } + *certdata_str_i = 0; + free(keybuf); + + const char *policy = "2.5.29.32.0"; // anyPolicy + int validated = pathfinder_dbus_verify(certdata_str, policy, 0, 0, &errmsg); + + if (!validated) + opkg_msg(ERROR, "Path verification failed: %s.\n", errmsg); + + free(certdata_str); + free(errmsg); + + return validated; +} +#endif + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7) +{ + STACK_OF(X509) *signers; + int i, ret = 1; /* signers are verified by default */ + + signers = PKCS7_get0_signers(p7, NULL, 0); + + for(i = 0; i < sk_X509_num(signers); i++){ + X509_STORE_CTX ctx = { + .cert = sk_X509_value(signers, i), + }; + + if(!pathfinder_verify_callback(&ctx, NULL)){ + /* Signer isn't verified ! goto jail; */ + ret = 0; + break; + } + } + + sk_X509_free(signers); + return ret; +} +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm) { + + SSL_CTX * ctx = (SSL_CTX *) sslctx; + SSL_CTX_set_cert_verify_callback(ctx, pathfinder_verify_callback, parm); + + return CURLE_OK ; +} +#endif diff --git a/src/libopkg/.svn/text-base/opkg_pathfinder.h.svn-base b/src/libopkg/.svn/text-base/opkg_pathfinder.h.svn-base new file mode 100644 index 0000000..89bebbd --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_pathfinder.h.svn-base @@ -0,0 +1,31 @@ +/* opkg_pathfinder.h - the opkg package management system + + + Copyright (C) 2009 Camille Moncelier <moncelier@devlife.org> + + 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, 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. +*/ + +#ifndef OPKG_PATHFINDER_H +#define OPKG_PATHFINDER_H + +#include "config.h" + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7); +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm); +#endif + + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_remove.c.svn-base b/src/libopkg/.svn/text-base/opkg_remove.c.svn-base new file mode 100644 index 0000000..5f4219b --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_remove.c.svn-base @@ -0,0 +1,450 @@ +/* opkg_remove.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> +#include <glob.h> +#include <unistd.h> + +#include "opkg_message.h" +#include "opkg_remove.h" +#include "opkg_cmd.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "libbb/libbb.h" + +/* + * Returns number of the number of packages depending on the packages provided by this package. + * Every package implicitly provides itself. + */ +int +pkg_has_installed_dependents(pkg_t *pkg, abstract_pkg_t *** pdependents) +{ + int nprovides = pkg->provides_count; + abstract_pkg_t **provides = pkg->provides; + unsigned int n_installed_dependents = 0; + int i; + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *providee = provides[i]; + abstract_pkg_t **dependers = providee->depended_upon_by; + abstract_pkg_t *dep_ab_pkg; + if (dependers == NULL) + continue; + while ((dep_ab_pkg = *dependers++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED || dep_ab_pkg->state_status == SS_UNPACKED){ + n_installed_dependents++; + } + } + + } + /* if caller requested the set of installed dependents */ + if (pdependents) { + int p = 0; + abstract_pkg_t **dependents = xcalloc((n_installed_dependents+1), sizeof(abstract_pkg_t *)); + + *pdependents = dependents; + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *providee = provides[i]; + abstract_pkg_t **dependers = providee->depended_upon_by; + abstract_pkg_t *dep_ab_pkg; + if (dependers == NULL) + continue; + while ((dep_ab_pkg = *dependers++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED && !(dep_ab_pkg->state_flag & SF_MARKED)) { + dependents[p++] = dep_ab_pkg; + dep_ab_pkg->state_flag |= SF_MARKED; + } + } + } + dependents[p] = NULL; + /* now clear the marks */ + for (i = 0; i < p; i++) { + abstract_pkg_t *dep_ab_pkg = dependents[i]; + dep_ab_pkg->state_flag &= ~SF_MARKED; + } + } + return n_installed_dependents; +} + +static int +opkg_remove_dependent_pkgs(pkg_t *pkg, abstract_pkg_t **dependents) +{ + int i; + int a; + int count; + pkg_vec_t *dependent_pkgs; + abstract_pkg_t * ab_pkg; + + if((ab_pkg = pkg->parent) == NULL){ + opkg_msg(ERROR, "Internal error: pkg %s isn't in hash table\n", + pkg->name); + return 0; + } + + if (dependents == NULL) + return 0; + + // here i am using the dependencies_checked + if (ab_pkg->dependencies_checked == 2) // variable to make out whether this package + return 0; // has already been encountered in the process + // of marking packages for removal - Karthik + ab_pkg->dependencies_checked = 2; + + i = 0; + count = 1; + dependent_pkgs = pkg_vec_alloc(); + + while (dependents [i] != NULL) { + abstract_pkg_t *dep_ab_pkg = dependents[i]; + + if (dep_ab_pkg->dependencies_checked == 2){ + i++; + continue; + } + if (dep_ab_pkg->state_status == SS_INSTALLED) { + for (a = 0; a < dep_ab_pkg->pkgs->len; a++) { + pkg_t *dep_pkg = dep_ab_pkg->pkgs->pkgs[a]; + if (dep_pkg->state_status == SS_INSTALLED) { + pkg_vec_insert(dependent_pkgs, dep_pkg); + count++; + } + } + } + i++; + /* 1 - to keep track of visited ab_pkgs when checking for possiblility of a broken removal of pkgs. + * 2 - to keep track of pkgs whose deps have been checked alrdy - Karthik */ + } + + if (count == 1) { + pkg_vec_free(dependent_pkgs); + return 0; + } + + + int err=0; + for (i = 0; i < dependent_pkgs->len; i++) { + err = opkg_remove_pkg(dependent_pkgs->pkgs[i],0); + if (err) + break; + } + pkg_vec_free(dependent_pkgs); + return err; +} + +static void +print_dependents_warning(pkg_t *pkg, abstract_pkg_t **dependents) +{ + abstract_pkg_t *dep_ab_pkg; + opkg_msg(ERROR, "Package %s is depended upon by packages:\n", pkg->name); + while ((dep_ab_pkg = *dependents++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED) + opkg_msg(ERROR, "\t%s\n", dep_ab_pkg->name); + } + opkg_msg(ERROR, "These might cease to work if package %s is removed.\n\n", + pkg->name); + opkg_msg(ERROR, "Force removal of this package with --force-depends.\n"); + opkg_msg(ERROR, "Force removal of this package and its dependents\n"); + opkg_msg(ERROR, "with --force-removal-of-dependent-packages.\n"); +} + +/* + * Find and remove packages that were autoinstalled and are orphaned + * by the removal of pkg. + */ +static int +remove_autoinstalled(pkg_t *pkg) +{ + int i, j; + int err = 0; + int n_deps; + pkg_t *p; + struct compound_depend *cdep; + abstract_pkg_t **dependents; + + int count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count; i++) { + cdep = &pkg->depends[i]; + if (cdep->type != PREDEPEND + && cdep->type != DEPEND + && cdep->type != RECOMMEND) + continue; + for (j=0; j<cdep->possibility_count; j++) { + p = pkg_hash_fetch_installed_by_name( + cdep->possibilities[j]->pkg->name); + + /* If the package is not installed, this could have + * been a circular dependency and the package has + * already been removed. + */ + if (!p) + return -1; + + if (!p->auto_installed) + continue; + + n_deps = pkg_has_installed_dependents(p, &dependents); + if (n_deps == 0) { + opkg_msg(NOTICE, "%s was autoinstalled and is " + "now orphaned, removing.\n", + p->name); + if (opkg_remove_pkg(p, 0) != 0) { + err = -1; + } + } else + opkg_msg(INFO, "%s was autoinstalled and is " + "still required by %d " + "installed packages.\n", + p->name, n_deps); + + if (dependents) + free(dependents); + } + } + + return err; +} + +int +opkg_remove_pkg(pkg_t *pkg, int from_upgrade) +{ + int err; + abstract_pkg_t *parent_pkg = NULL; + +/* + * If called from an upgrade and not from a normal remove, + * ignore the essential flag. + */ + if (pkg->essential && !from_upgrade) { + if (conf->force_removal_of_essential_packages) { + opkg_msg(NOTICE, + "Removing essential package %s under your coercion.\n" + "\tIf your system breaks, you get to keep both pieces\n", + pkg->name); + } else { + opkg_msg(NOTICE, "Refusing to remove essential package %s.\n" + "\tRemoving an essential package may lead to an unusable system, but if\n" + "\tyou enjoy that kind of pain, you can force opkg to proceed against\n" + "\tits will with the option: --force-removal-of-essential-packages\n", + pkg->name); + return -1; + } + } + + if ((parent_pkg = pkg->parent) == NULL) + return 0; + + /* only attempt to remove dependent installed packages if + * force_depends is not specified or the package is being + * replaced. + */ + if (!conf->force_depends + && !(pkg->state_flag & SF_REPLACE)) { + abstract_pkg_t **dependents; + int has_installed_dependents = + pkg_has_installed_dependents(pkg, &dependents); + + if (has_installed_dependents) { + /* + * if this package is depended upon by others, then either we should + * not remove it or we should remove it and all of its dependents + */ + + if (!conf->force_removal_of_dependent_packages) { + print_dependents_warning(pkg, dependents); + free(dependents); + return -1; + } + + /* remove packages depending on this package - Karthik */ + err = opkg_remove_dependent_pkgs(pkg, dependents); + if (err) { + free(dependents); + return err; + } + } + if (dependents) + free(dependents); + } + + if (from_upgrade == 0) { + opkg_msg(NOTICE, "Removing package %s from %s...\n", + pkg->name, pkg->dest->name); + } + pkg->state_flag |= SF_FILELIST_CHANGED; + + pkg->state_want = SW_DEINSTALL; + opkg_state_changed++; + + if (pkg_run_script(pkg, "prerm", "remove") != 0) { + if (!conf->force_remove) { + opkg_msg(ERROR, "not removing package \"%s\", " + "prerm script failed\n", pkg->name); + opkg_msg(NOTICE, "You can force removal of packages with failed " + "prerm scripts with the option: \n" + "\t--force-remove\n"); + return -1; + } + } + + /* DPKG_INCOMPATIBILITY: dpkg is slightly different here. It + maintains an empty filelist rather than deleting it. That seems + like a big pain, and I don't see that that should make a big + difference, but for anyone who wants tighter compatibility, + feel free to fix this. */ + remove_data_files_and_list(pkg); + + err = pkg_run_script(pkg, "postrm", "remove"); + + remove_maintainer_scripts(pkg); + pkg->state_status = SS_NOT_INSTALLED; + + if (parent_pkg) + parent_pkg->state_status = SS_NOT_INSTALLED; + + /* remove autoinstalled packages that are orphaned by the removal of this one */ + if (conf->autoremove) { + if (remove_autoinstalled(pkg) != 0) { + err = -1; + } + } + return err; +} + +void +remove_data_files_and_list(pkg_t *pkg) +{ + str_list_t installed_dirs; + str_list_t *installed_files; + str_list_elt_t *iter; + char *file_name; + conffile_t *conffile; + int removed_a_dir; + pkg_t *owner; + int rootdirlen = 0; + + installed_files = pkg_get_installed_files(pkg); + if (installed_files == NULL) { + opkg_msg(ERROR, "Failed to determine installed " + "files for %s. None removed.\n", pkg->name); + return; + } + + str_list_init(&installed_dirs); + + /* don't include trailing slash */ + if (conf->offline_root) + rootdirlen = strlen(conf->offline_root); + + for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) { + file_name = (char *)iter->data; + + owner = file_hash_get_file_owner(file_name); + if (owner != pkg) + /* File may have been claimed by another package. */ + continue; + + if (file_is_dir(file_name)) { + str_list_append(&installed_dirs, file_name); + continue; + } + + conffile = pkg_get_conffile(pkg, file_name+rootdirlen); + if (conffile) { + if (conffile_has_been_modified(conffile)) { + opkg_msg(NOTICE, "Not deleting modified conffile %s.\n", + file_name); + continue; + } + } + + if (!conf->noaction) { + opkg_msg(INFO, "Deleting %s.\n", file_name); + unlink(file_name); + } else + opkg_msg(INFO, "Not deleting %s. (noaction)\n", + file_name); + + file_hash_remove(file_name); + } + + /* Remove empty directories */ + if (!conf->noaction) { + do { + removed_a_dir = 0; + for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) { + file_name = (char *)iter->data; + + if (rmdir(file_name) == 0) { + opkg_msg(INFO, "Deleting %s.\n", file_name); + removed_a_dir = 1; + str_list_remove(&installed_dirs, &iter); + } + } + } while (removed_a_dir); + } + + pkg_free_installed_files(pkg); + pkg_remove_installed_files_list(pkg); + + /* Don't print warning for dirs that are provided by other packages */ + for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) { + file_name = (char *)iter->data; + + owner = file_hash_get_file_owner(file_name); + if (owner) { + free(iter->data); + iter->data = NULL; + str_list_remove(&installed_dirs, &iter); + } + } + + /* cleanup */ + while (!void_list_empty(&installed_dirs)) { + iter = str_list_pop(&installed_dirs); + free(iter->data); + free(iter); + } + str_list_deinit(&installed_dirs); +} + +void +remove_maintainer_scripts(pkg_t *pkg) +{ + int i, err; + char *globpattern; + glob_t globbuf; + + if (conf->noaction) + return; + + sprintf_alloc(&globpattern, "%s/%s.*", + pkg->dest->info_dir, pkg->name); + + err = glob(globpattern, 0, NULL, &globbuf); + free(globpattern); + if (err) + return; + + for (i = 0; i < globbuf.gl_pathc; i++) { + opkg_msg(INFO, "Deleting %s.\n", globbuf.gl_pathv[i]); + unlink(globbuf.gl_pathv[i]); + } + globfree(&globbuf); +} diff --git a/src/libopkg/.svn/text-base/opkg_remove.h.svn-base b/src/libopkg/.svn/text-base/opkg_remove.h.svn-base new file mode 100644 index 0000000..f0c45d2 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_remove.h.svn-base @@ -0,0 +1,30 @@ +/* opkg_remove.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_REMOVE_H +#define OPKG_REMOVE_H + +#include "pkg.h" +#include "opkg_conf.h" + +int opkg_remove_pkg(pkg_t *pkg,int message); +int pkg_has_installed_dependents(pkg_t *pkg, abstract_pkg_t *** pdependents); +void remove_data_files_and_list(pkg_t *pkg); +void remove_maintainer_scripts(pkg_t *pkg); + + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_upgrade.c.svn-base b/src/libopkg/.svn/text-base/opkg_upgrade.c.svn-base new file mode 100644 index 0000000..10b8217 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_upgrade.c.svn-base @@ -0,0 +1,130 @@ +/* opkg_upgrade.c - the opkg package management system + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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, 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. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "opkg_install.h" +#include "opkg_upgrade.h" +#include "opkg_message.h" + +int +opkg_upgrade_pkg(pkg_t *old) +{ + pkg_t *new; + int cmp; + char *old_version, *new_version; + + if (old->state_flag & SF_HOLD) { + opkg_msg(NOTICE, "Not upgrading package %s which is marked " + "hold (flags=%#x).\n", old->name, old->state_flag); + return 0; + } + + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + if (new == NULL) { + old_version = pkg_version_str_alloc(old); + opkg_msg(NOTICE, "Assuming locally installed package %s (%s) " + "is up to date.\n", old->name, old_version); + free(old_version); + return 0; + } + + old_version = pkg_version_str_alloc(old); + new_version = pkg_version_str_alloc(new); + + cmp = pkg_compare_versions(old, new); + opkg_msg(DEBUG, "Comparing visible versions of pkg %s:" + "\n\t%s is installed " + "\n\t%s is available " + "\n\t%d was comparison result\n", + old->name, old_version, new_version, cmp); + if (cmp == 0) { + opkg_msg(INFO, "Package %s (%s) installed in %s is up to date.\n", + old->name, old_version, old->dest->name); + free(old_version); + free(new_version); + return 0; + } else if (cmp > 0) { + opkg_msg(NOTICE, "Not downgrading package %s on %s from %s to %s.\n", + old->name, old->dest->name, old_version, new_version); + free(old_version); + free(new_version); + return 0; + } else if (cmp < 0) { + new->dest = old->dest; + old->state_want = SW_DEINSTALL; + } + + free(old_version); + free(new_version); + new->state_flag |= SF_USER; + return opkg_install_pkg(new,1); +} + + +static void +pkg_hash_check_installed_pkg_helper(const char *pkg_name, void *entry, + void *data) +{ + struct active_list *head = (struct active_list *) data; + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + int j; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (pkg->state_status == SS_INSTALLED + || pkg->state_status == SS_UNPACKED) + active_list_add(head, &pkg->list); + } +} + +struct active_list * +prepare_upgrade_list(void) +{ + struct active_list *head = active_list_head_new(); + struct active_list *all = active_list_head_new(); + struct active_list *node=NULL; + + /* ensure all data is valid */ + pkg_info_preinstall_check(); + + hash_table_foreach(&conf->pkg_hash, pkg_hash_check_installed_pkg_helper, all); + for (node=active_list_next(all,all); node; node = active_list_next(all, node)) { + pkg_t *old, *new; + int cmp; + + old = list_entry(node, pkg_t, list); + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + + if (new == NULL) + continue; + + cmp = pkg_compare_versions(old, new); + + if ( cmp < 0 ) { + node = active_list_move_node(all, head, &old->list); + } + } + active_list_head_delete(all); + return head; +} diff --git a/src/libopkg/.svn/text-base/opkg_upgrade.h.svn-base b/src/libopkg/.svn/text-base/opkg_upgrade.h.svn-base new file mode 100644 index 0000000..6545fa8 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_upgrade.h.svn-base @@ -0,0 +1,22 @@ +/* opkg_upgrade.c - the opkg package management system + + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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, 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. +*/ +#ifndef OPKG_UPGRADE_H +#define OPKG_UPGRADE_H + +#include "active_list.h" +int opkg_upgrade_pkg(pkg_t *old); +struct active_list * prepare_upgrade_list (void); + +#endif diff --git a/src/libopkg/.svn/text-base/opkg_utils.c.svn-base b/src/libopkg/.svn/text-base/opkg_utils.c.svn-base new file mode 100644 index 0000000..ebe4fa8 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_utils.c.svn-base @@ -0,0 +1,78 @@ +/* opkg_utils.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <ctype.h> +#include <sys/statvfs.h> + +#include "libbb/libbb.h" + +unsigned long +get_available_kbytes(char * filesystem) +{ + struct statvfs f; + + if (statvfs(filesystem, &f) == -1) { + opkg_perror(ERROR, "Failed to statvfs for %s", filesystem); + return 0; + } + + // Actually ((sfs.f_bavail * sfs.f_frsize) / 1024) + // and here we try to avoid overflow. + if (f.f_frsize >= 1024) + return (f.f_bavail * (f.f_frsize / 1024)); + else if (f.f_frsize > 0) + return f.f_bavail / (1024 / f.f_frsize); + + opkg_msg(ERROR, "Unknown block size for target filesystem.\n"); + + return 0; +} + +/* something to remove whitespace, a hash pooper */ +char *trim_xstrdup(const char *src) +{ + const char *end; + + /* remove it from the front */ + while(src && + isspace(*src) && + *src) + src++; + + end = src + (strlen(src) - 1); + + /* and now from the back */ + while((end > src) && + isspace(*end)) + end--; + + end++; + + /* xstrndup will NULL terminate for us */ + return xstrndup(src, end-src); +} + +int line_is_blank(const char *line) +{ + const char *s; + + for (s = line; *s; s++) { + if (!isspace(*s)) + return 0; + } + return 1; +} diff --git a/src/libopkg/.svn/text-base/opkg_utils.h.svn-base b/src/libopkg/.svn/text-base/opkg_utils.h.svn-base new file mode 100644 index 0000000..092d158 --- /dev/null +++ b/src/libopkg/.svn/text-base/opkg_utils.h.svn-base @@ -0,0 +1,25 @@ +/* opkg_utils.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef OPKG_UTILS_H +#define OPKG_UTILS_H + +unsigned long get_available_kbytes(char * filesystem); +char *trim_xstrdup(const char *line); +int line_is_blank(const char *line); + +#endif diff --git a/src/libopkg/.svn/text-base/parse_util.c.svn-base b/src/libopkg/.svn/text-base/parse_util.c.svn-base new file mode 100644 index 0000000..54850a8 --- /dev/null +++ b/src/libopkg/.svn/text-base/parse_util.c.svn-base @@ -0,0 +1,168 @@ +/* parse_util.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Steven M. Ayer + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <ctype.h> + +#include "opkg_utils.h" +#include "libbb/libbb.h" + +#include "parse_util.h" + +int +is_field(const char *type, const char *line) +{ + if (!strncmp(line, type, strlen(type))) + return 1; + return 0; +} + +char * +parse_simple(const char *type, const char *line) +{ + return trim_xstrdup(line + strlen(type) + 1); +} + +/* + * Parse a comma separated string into an array. + */ +char ** +parse_list(const char *raw, unsigned int *count, const char sep, int skip_field) +{ + char **depends = NULL; + const char *start, *end; + int line_count = 0; + + /* skip past the "Field:" marker */ + if (!skip_field) { + while (*raw && *raw != ':') + raw++; + raw++; + } + + if (line_is_blank(raw)) { + *count = line_count; + return NULL; + } + + while (*raw) { + depends = xrealloc(depends, sizeof(char *) * (line_count + 1)); + + while (isspace(*raw)) + raw++; + + start = raw; + while (*raw != sep && *raw) + raw++; + end = raw; + + while (end > start && isspace(*end)) + end--; + + if (sep == ' ') + end++; + + depends[line_count] = xstrndup(start, end-start); + + line_count++; + if (*raw == sep) + raw++; + } + + *count = line_count; + return depends; +} + +int +parse_from_stream_nomalloc(parse_line_t parse_line, void *ptr, FILE *fp, uint mask, + char **buf0, size_t buf0len) +{ + int ret, lineno; + char *buf, *nl; + size_t buflen; + + lineno = 1; + ret = 0; + + buflen = buf0len; + buf = *buf0; + buf[0] = '\0'; + + while (1) { + if (fgets(buf, (int)buflen, fp) == NULL) { + if (ferror(fp)) { + opkg_perror(ERROR, "fgets"); + ret = -1; + } else if (strlen(*buf0) == buf0len-1) { + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(ptr, *buf0, mask); + } + break; + } + + nl = strchr(buf, '\n'); + if (nl == NULL) { + if (strlen(buf) < buflen-1) { + /* + * Line could be exactly buflen-1 long and + * missing a newline, but we won't know until + * fgets fails to read more data. + */ + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(ptr, *buf0, mask); + break; + } + if (buf0len >= EXCESSIVE_LINE_LEN) { + opkg_msg(ERROR, "Excessively long line at " + "%d. Corrupt file?\n", + lineno); + ret = -1; + break; + } + + /* + * Realloc and point buf past the data already read, + * at the NULL terminator inserted by fgets. + * |<--------------- buf0len ----------------->| + * | |<------- buflen ---->| + * |---------------------|---------------------| + * buf0 buf + */ + buflen = buf0len +1; + buf0len *= 2; + *buf0 = xrealloc(*buf0, buf0len); + buf = *buf0 + buflen -2; + + continue; + } + + *nl = '\0'; + + lineno++; + + if (parse_line(ptr, *buf0, mask)) + break; + + buf = *buf0; + buflen = buf0len; + buf[0] = '\0'; + } + + return ret; +} diff --git a/src/libopkg/.svn/text-base/parse_util.h.svn-base b/src/libopkg/.svn/text-base/parse_util.h.svn-base new file mode 100644 index 0000000..26e2d5b --- /dev/null +++ b/src/libopkg/.svn/text-base/parse_util.h.svn-base @@ -0,0 +1,31 @@ +/* parse_util.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PARSE_UTIL_H +#define PARSE_UTIL_H + +int is_field(const char *type, const char *line); +char *parse_simple(const char *type, const char *line); +char **parse_list(const char *raw, unsigned int *count, const char sep, int skip_field); + +typedef int (*parse_line_t)(void *, const char *, uint); +int parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask, + char **buf0, size_t buf0len); + +#define EXCESSIVE_LINE_LEN (4096 << 8) + +#endif diff --git a/src/libopkg/.svn/text-base/pkg.c.svn-base b/src/libopkg/.svn/text-base/pkg.c.svn-base new file mode 100644 index 0000000..d8c3984 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg.c.svn-base @@ -0,0 +1,1428 @@ +/* pkg.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <libgen.h> + +#include "pkg.h" + +#include "pkg_parse.h" +#include "pkg_extract.h" +#include "opkg_message.h" +#include "opkg_utils.h" + +#include "libbb/libbb.h" +#include "sprintf_alloc.h" +#include "file_util.h" +#include "xsystem.h" +#include "opkg_conf.h" + +typedef struct enum_map enum_map_t; +struct enum_map +{ + unsigned int value; + const char *str; +}; + +static const enum_map_t pkg_state_want_map[] = { + { SW_UNKNOWN, "unknown"}, + { SW_INSTALL, "install"}, + { SW_DEINSTALL, "deinstall"}, + { SW_PURGE, "purge"} +}; + +static const enum_map_t pkg_state_flag_map[] = { + { SF_OK, "ok"}, + { SF_REINSTREQ, "reinstreq"}, + { SF_HOLD, "hold"}, + { SF_REPLACE, "replace"}, + { SF_NOPRUNE, "noprune"}, + { SF_PREFER, "prefer"}, + { SF_OBSOLETE, "obsolete"}, + { SF_USER, "user"}, +}; + +static const enum_map_t pkg_state_status_map[] = { + { SS_NOT_INSTALLED, "not-installed" }, + { SS_UNPACKED, "unpacked" }, + { SS_HALF_CONFIGURED, "half-configured" }, + { SS_INSTALLED, "installed" }, + { SS_HALF_INSTALLED, "half-installed" }, + { SS_CONFIG_FILES, "config-files" }, + { SS_POST_INST_FAILED, "post-inst-failed" }, + { SS_REMOVAL_FAILED, "removal-failed" } +}; + +static void +pkg_init(pkg_t *pkg) +{ + pkg->name = NULL; + pkg->epoch = 0; + pkg->version = NULL; + pkg->revision = NULL; + pkg->dest = NULL; + pkg->src = NULL; + pkg->architecture = NULL; + pkg->maintainer = NULL; + pkg->section = NULL; + pkg->description = NULL; + pkg->state_want = SW_UNKNOWN; + pkg->state_flag = SF_OK; + pkg->state_status = SS_NOT_INSTALLED; + pkg->depends_str = NULL; + pkg->provides_str = NULL; + pkg->depends_count = 0; + pkg->depends = NULL; + pkg->suggests_str = NULL; + pkg->recommends_str = NULL; + pkg->suggests_count = 0; + pkg->recommends_count = 0; + + active_list_init(&pkg->list); + + pkg->conflicts = NULL; + pkg->conflicts_count = 0; + + pkg->replaces = NULL; + pkg->replaces_count = 0; + + pkg->pre_depends_count = 0; + pkg->pre_depends_str = NULL; + pkg->provides_count = 0; + pkg->provides = NULL; + pkg->filename = NULL; + pkg->local_filename = NULL; + pkg->tmp_unpack_dir = NULL; + pkg->md5sum = NULL; +#if defined HAVE_SHA256 + pkg->sha256sum = NULL; +#endif + pkg->size = 0; + pkg->installed_size = 0; + pkg->priority = NULL; + pkg->source = NULL; + conffile_list_init(&pkg->conffiles); + pkg->installed_files = NULL; + pkg->installed_files_ref_cnt = 0; + pkg->essential = 0; + pkg->provided_by_hand = 0; +} + +pkg_t * +pkg_new(void) +{ + pkg_t *pkg; + + pkg = xcalloc(1, sizeof(pkg_t)); + pkg_init(pkg); + + return pkg; +} + +static void +compound_depend_deinit(compound_depend_t *depends) +{ + int i; + for (i = 0; i < depends->possibility_count; i++) + { + depend_t *d; + d = depends->possibilities[i]; + free (d->version); + free (d); + } + free (depends->possibilities); +} + +void +pkg_deinit(pkg_t *pkg) +{ + int i; + + if (pkg->name) + free(pkg->name); + pkg->name = NULL; + + pkg->epoch = 0; + + if (pkg->version) + free(pkg->version); + pkg->version = NULL; + /* revision shares storage with version, so don't free */ + pkg->revision = NULL; + + /* owned by opkg_conf_t */ + pkg->dest = NULL; + /* owned by opkg_conf_t */ + pkg->src = NULL; + + if (pkg->architecture) + free(pkg->architecture); + pkg->architecture = NULL; + + if (pkg->maintainer) + free(pkg->maintainer); + pkg->maintainer = NULL; + + if (pkg->section) + free(pkg->section); + pkg->section = NULL; + + if (pkg->description) + free(pkg->description); + pkg->description = NULL; + + pkg->state_want = SW_UNKNOWN; + pkg->state_flag = SF_OK; + pkg->state_status = SS_NOT_INSTALLED; + + active_list_clear(&pkg->list); + + if (pkg->replaces) + free (pkg->replaces); + pkg->replaces = NULL; + + if (pkg->depends) { + int count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count; i++) + compound_depend_deinit (&pkg->depends[i]); + free (pkg->depends); + } + + if (pkg->conflicts) { + for (i=0; i<pkg->conflicts_count; i++) + compound_depend_deinit (&pkg->conflicts[i]); + free (pkg->conflicts); + } + + if (pkg->provides) + free (pkg->provides); + + pkg->pre_depends_count = 0; + pkg->provides_count = 0; + + if (pkg->filename) + free(pkg->filename); + pkg->filename = NULL; + + if (pkg->local_filename) + free(pkg->local_filename); + pkg->local_filename = NULL; + + /* CLEANUP: It'd be nice to pullin the cleanup function from + opkg_install.c here. See comment in + opkg_install.c:cleanup_temporary_files */ + if (pkg->tmp_unpack_dir) + free(pkg->tmp_unpack_dir); + pkg->tmp_unpack_dir = NULL; + + if (pkg->md5sum) + free(pkg->md5sum); + pkg->md5sum = NULL; + +#if defined HAVE_SHA256 + if (pkg->sha256sum) + free(pkg->sha256sum); + pkg->sha256sum = NULL; +#endif + + if (pkg->priority) + free(pkg->priority); + pkg->priority = NULL; + + if (pkg->source) + free(pkg->source); + pkg->source = NULL; + + conffile_list_deinit(&pkg->conffiles); + + /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so, + since if they are calling deinit, they should know. Maybe do an + assertion here instead? */ + pkg->installed_files_ref_cnt = 1; + pkg_free_installed_files(pkg); + pkg->essential = 0; + + if (pkg->tags) + free (pkg->tags); + pkg->tags = NULL; +} + +int +pkg_init_from_file(pkg_t *pkg, const char *filename) +{ + int fd, err = 0; + FILE *control_file; + char *control_path, *tmp; + + pkg_init(pkg); + + pkg->local_filename = xstrdup(filename); + + tmp = xstrdup(filename); + sprintf_alloc(&control_path, "%s/%s.control.XXXXXX", + conf->tmp_dir, + basename(tmp)); + free(tmp); + fd = mkstemp(control_path); + if (fd == -1) { + opkg_perror(ERROR, "Failed to make temp file %s", control_path); + err = -1; + goto err0; + } + + control_file = fdopen(fd, "r+"); + if (control_file == NULL) { + opkg_perror(ERROR, "Failed to fdopen %s", control_path); + close(fd); + err = -1; + goto err1; + } + + err = pkg_extract_control_file_to_stream(pkg, control_file); + if (err) { + opkg_msg(ERROR, "Failed to extract control file from %s.\n", + filename); + goto err2; + } + + rewind(control_file); + + if ((err = pkg_parse_from_stream(pkg, control_file, 0))) { + if (err == 1) { + opkg_msg(ERROR, "Malformed package file %s.\n", + filename); + } + err = -1; + } + +err2: + fclose(control_file); +err1: + unlink(control_path); +err0: + free(control_path); + + return err; +} + +/* Merge any new information in newpkg into oldpkg */ +int +pkg_merge(pkg_t *oldpkg, pkg_t *newpkg) +{ + if (oldpkg == newpkg) { + return 0; + } + + if (!oldpkg->auto_installed) + oldpkg->auto_installed = newpkg->auto_installed; + + if (!oldpkg->src) + oldpkg->src = newpkg->src; + if (!oldpkg->dest) + oldpkg->dest = newpkg->dest; + if (!oldpkg->architecture) + oldpkg->architecture = xstrdup(newpkg->architecture); + if (!oldpkg->arch_priority) + oldpkg->arch_priority = newpkg->arch_priority; + if (!oldpkg->section) + oldpkg->section = xstrdup(newpkg->section); + if(!oldpkg->maintainer) + oldpkg->maintainer = xstrdup(newpkg->maintainer); + if(!oldpkg->description) + oldpkg->description = xstrdup(newpkg->description); + + if (!oldpkg->depends_count && !oldpkg->pre_depends_count && !oldpkg->recommends_count && !oldpkg->suggests_count) { + oldpkg->depends_count = newpkg->depends_count; + newpkg->depends_count = 0; + + oldpkg->depends = newpkg->depends; + newpkg->depends = NULL; + + oldpkg->pre_depends_count = newpkg->pre_depends_count; + newpkg->pre_depends_count = 0; + + oldpkg->recommends_count = newpkg->recommends_count; + newpkg->recommends_count = 0; + + oldpkg->suggests_count = newpkg->suggests_count; + newpkg->suggests_count = 0; + } + + if (oldpkg->provides_count <= 1) { + oldpkg->provides_count = newpkg->provides_count; + newpkg->provides_count = 0; + + if (!oldpkg->provides) { + oldpkg->provides = newpkg->provides; + newpkg->provides = NULL; + } + } + + if (!oldpkg->conflicts_count) { + oldpkg->conflicts_count = newpkg->conflicts_count; + newpkg->conflicts_count = 0; + + oldpkg->conflicts = newpkg->conflicts; + newpkg->conflicts = NULL; + } + + if (!oldpkg->replaces_count) { + oldpkg->replaces_count = newpkg->replaces_count; + newpkg->replaces_count = 0; + + oldpkg->replaces = newpkg->replaces; + newpkg->replaces = NULL; + } + + if (!oldpkg->filename) + oldpkg->filename = xstrdup(newpkg->filename); + if (!oldpkg->local_filename) + oldpkg->local_filename = xstrdup(newpkg->local_filename); + if (!oldpkg->tmp_unpack_dir) + oldpkg->tmp_unpack_dir = xstrdup(newpkg->tmp_unpack_dir); + if (!oldpkg->md5sum) + oldpkg->md5sum = xstrdup(newpkg->md5sum); +#if defined HAVE_SHA256 + if (!oldpkg->sha256sum) + oldpkg->sha256sum = xstrdup(newpkg->sha256sum); +#endif + if (!oldpkg->size) + oldpkg->size = newpkg->size; + if (!oldpkg->installed_size) + oldpkg->installed_size = newpkg->installed_size; + if (!oldpkg->priority) + oldpkg->priority = xstrdup(newpkg->priority); + if (!oldpkg->source) + oldpkg->source = xstrdup(newpkg->source); + + if (nv_pair_list_empty(&oldpkg->conffiles)){ + list_splice_init(&newpkg->conffiles.head, &oldpkg->conffiles.head); + } + + if (!oldpkg->installed_files){ + oldpkg->installed_files = newpkg->installed_files; + oldpkg->installed_files_ref_cnt = newpkg->installed_files_ref_cnt; + newpkg->installed_files = NULL; + } + + if (!oldpkg->essential) + oldpkg->essential = newpkg->essential; + + return 0; +} + +static void +abstract_pkg_init(abstract_pkg_t *ab_pkg) +{ + ab_pkg->provided_by = abstract_pkg_vec_alloc(); + ab_pkg->dependencies_checked = 0; + ab_pkg->state_status = SS_NOT_INSTALLED; +} + +abstract_pkg_t * +abstract_pkg_new(void) +{ + abstract_pkg_t * ab_pkg; + + ab_pkg = xcalloc(1, sizeof(abstract_pkg_t)); + abstract_pkg_init(ab_pkg); + + return ab_pkg; +} + +void +set_flags_from_control(pkg_t *pkg){ + char *file_name; + FILE *fp; + + sprintf_alloc(&file_name,"%s/%s.control", pkg->dest->info_dir, pkg->name); + + fp = fopen(file_name, "r"); + if (fp == NULL) { + opkg_perror(ERROR, "Failed to open %s", file_name); + free(file_name); + return; + } + + free(file_name); + + if (pkg_parse_from_stream(pkg, fp, PFM_ALL ^ PFM_ESSENTIAL)) { + opkg_msg(DEBUG, "Unable to read control file for %s. May be empty.\n", + pkg->name); + } + + fclose(fp); + + return; +} + +static const char * +pkg_state_want_to_str(pkg_state_want_t sw) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) { + if (pkg_state_want_map[i].value == sw) { + return pkg_state_want_map[i].str; + } + } + + opkg_msg(ERROR, "Internal error: state_want=%d\n", sw); + return "<STATE_WANT_UNKNOWN>"; +} + +pkg_state_want_t +pkg_state_want_from_str(char *str) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) { + if (strcmp(str, pkg_state_want_map[i].str) == 0) { + return pkg_state_want_map[i].value; + } + } + + opkg_msg(ERROR, "Internal error: state_want=%s\n", str); + return SW_UNKNOWN; +} + +static char * +pkg_state_flag_to_str(pkg_state_flag_t sf) +{ + int i; + unsigned int len; + char *str; + + /* clear the temporary flags before converting to string */ + sf &= SF_NONVOLATILE_FLAGS; + + if (sf == 0) + return xstrdup("ok"); + + len = 0; + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + if (sf & pkg_state_flag_map[i].value) + len += strlen(pkg_state_flag_map[i].str) + 1; + } + + str = xmalloc(len+1); + str[0] = '\0'; + + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + if (sf & pkg_state_flag_map[i].value) { + strncat(str, pkg_state_flag_map[i].str, len); + strncat(str, ",", len); + } + } + + len = strlen(str); + str[len-1] = '\0'; /* squash last comma */ + + return str; +} + +pkg_state_flag_t +pkg_state_flag_from_str(const char *str) +{ + int i; + int sf = SF_OK; + const char *sfname; + unsigned int sfname_len; + + if (strcmp(str, "ok") == 0) { + return SF_OK; + } + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + sfname = pkg_state_flag_map[i].str; + sfname_len = strlen(sfname); + if (strncmp(str, sfname, sfname_len) == 0) { + sf |= pkg_state_flag_map[i].value; + str += sfname_len; + if (str[0] == ',') { + str++; + } else { + break; + } + } + } + + return sf; +} + +static const char * +pkg_state_status_to_str(pkg_state_status_t ss) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) { + if (pkg_state_status_map[i].value == ss) { + return pkg_state_status_map[i].str; + } + } + + opkg_msg(ERROR, "Internal error: state_status=%d\n", ss); + return "<STATE_STATUS_UNKNOWN>"; +} + +pkg_state_status_t +pkg_state_status_from_str(const char *str) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) { + if (strcmp(str, pkg_state_status_map[i].str) == 0) { + return pkg_state_status_map[i].value; + } + } + + opkg_msg(ERROR, "Internal error: state_status=%s\n", str); + return SS_NOT_INSTALLED; +} + +void +pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field) +{ + int i, j; + char *str; + int depends_count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) { + goto UNKNOWN_FMT_FIELD; + } + + switch (field[0]) + { + case 'a': + case 'A': + if (strcasecmp(field, "Architecture") == 0) { + if (pkg->architecture) { + fprintf(fp, "Architecture: %s\n", pkg->architecture); + } + } else if (strcasecmp(field, "Auto-Installed") == 0) { + if (pkg->auto_installed) + fprintf(fp, "Auto-Installed: yes\n"); + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'c': + case 'C': + if (strcasecmp(field, "Conffiles") == 0) { + conffile_list_elt_t *iter; + + if (nv_pair_list_empty(&pkg->conffiles)) + return; + + fprintf(fp, "Conffiles:\n"); + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + if (((conffile_t *)iter->data)->name && ((conffile_t *)iter->data)->value) { + fprintf(fp, " %s %s\n", + ((conffile_t *)iter->data)->name, + ((conffile_t *)iter->data)->value); + } + } + } else if (strcasecmp(field, "Conflicts") == 0) { + struct depend *cdep; + if (pkg->conflicts_count) { + fprintf(fp, "Conflicts:"); + for(i = 0; i < pkg->conflicts_count; i++) { + cdep = pkg->conflicts[i].possibilities[0]; + fprintf(fp, "%s %s", i == 0 ? "" : ",", + cdep->pkg->name); + if (cdep->version) { + fprintf(fp, " (%s%s)", + constraint_to_str(cdep->constraint), + cdep->version); + } + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'd': + case 'D': + if (strcasecmp(field, "Depends") == 0) { + if (pkg->depends_count) { + fprintf(fp, "Depends:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != DEPEND) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else if (strcasecmp(field, "Description") == 0) { + if (pkg->description) { + fprintf(fp, "Description: %s\n", pkg->description); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'e': + case 'E': + if (pkg->essential) { + fprintf(fp, "Essential: yes\n"); + } + break; + case 'f': + case 'F': + if (pkg->filename) { + fprintf(fp, "Filename: %s\n", pkg->filename); + } + break; + case 'i': + case 'I': + if (strcasecmp(field, "Installed-Size") == 0) { + fprintf(fp, "Installed-Size: %ld\n", pkg->installed_size); + } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) { + fprintf(fp, "Installed-Time: %lu\n", pkg->installed_time); + } + break; + case 'm': + case 'M': + if (strcasecmp(field, "Maintainer") == 0) { + if (pkg->maintainer) { + fprintf(fp, "Maintainer: %s\n", pkg->maintainer); + } + } else if (strcasecmp(field, "MD5sum") == 0) { + if (pkg->md5sum) { + fprintf(fp, "MD5Sum: %s\n", pkg->md5sum); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'p': + case 'P': + if (strcasecmp(field, "Package") == 0) { + fprintf(fp, "Package: %s\n", pkg->name); + } else if (strcasecmp(field, "Priority") == 0) { + fprintf(fp, "Priority: %s\n", pkg->priority); + } else if (strcasecmp(field, "Provides") == 0) { + if (pkg->provides_count) { + fprintf(fp, "Provides:"); + for(i = 1; i < pkg->provides_count; i++) { + fprintf(fp, "%s %s", i == 1 ? "" : ",", + pkg->provides[i]->name); + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'r': + case 'R': + if (strcasecmp (field, "Replaces") == 0) { + if (pkg->replaces_count) { + fprintf(fp, "Replaces:"); + for (i = 0; i < pkg->replaces_count; i++) { + fprintf(fp, "%s %s", i == 0 ? "" : ",", + pkg->replaces[i]->name); + } + fprintf(fp, "\n"); + } + } else if (strcasecmp (field, "Recommends") == 0) { + if (pkg->recommends_count) { + fprintf(fp, "Recommends:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != RECOMMEND) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 's': + case 'S': + if (strcasecmp(field, "Section") == 0) { + if (pkg->section) { + fprintf(fp, "Section: %s\n", pkg->section); + } +#if defined HAVE_SHA256 + } else if (strcasecmp(field, "SHA256sum") == 0) { + if (pkg->sha256sum) { + fprintf(fp, "SHA256sum: %s\n", pkg->sha256sum); + } +#endif + } else if (strcasecmp(field, "Size") == 0) { + if (pkg->size) { + fprintf(fp, "Size: %ld\n", pkg->size); + } + } else if (strcasecmp(field, "Source") == 0) { + if (pkg->source) { + fprintf(fp, "Source: %s\n", pkg->source); + } + } else if (strcasecmp(field, "Status") == 0) { + char *pflag = pkg_state_flag_to_str(pkg->state_flag); + fprintf(fp, "Status: %s %s %s\n", + pkg_state_want_to_str(pkg->state_want), + pflag, + pkg_state_status_to_str(pkg->state_status)); + free(pflag); + } else if (strcasecmp(field, "Suggests") == 0) { + if (pkg->suggests_count) { + fprintf(fp, "Suggests:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != SUGGEST) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 't': + case 'T': + if (strcasecmp(field, "Tags") == 0) { + if (pkg->tags) { + fprintf(fp, "Tags: %s\n", pkg->tags); + } + } + break; + case 'v': + case 'V': + { + char *version = pkg_version_str_alloc(pkg); + if (version == NULL) + return; + fprintf(fp, "Version: %s\n", version); + free(version); + } + break; + default: + goto UNKNOWN_FMT_FIELD; + } + + return; + +UNKNOWN_FMT_FIELD: + opkg_msg(ERROR, "Internal error: field=%s\n", field); +} + +void +pkg_formatted_info(FILE *fp, pkg_t *pkg) +{ + pkg_formatted_field(fp, pkg, "Package"); + pkg_formatted_field(fp, pkg, "Version"); + pkg_formatted_field(fp, pkg, "Depends"); + pkg_formatted_field(fp, pkg, "Recommends"); + pkg_formatted_field(fp, pkg, "Suggests"); + pkg_formatted_field(fp, pkg, "Provides"); + pkg_formatted_field(fp, pkg, "Replaces"); + pkg_formatted_field(fp, pkg, "Conflicts"); + pkg_formatted_field(fp, pkg, "Status"); + pkg_formatted_field(fp, pkg, "Section"); + pkg_formatted_field(fp, pkg, "Essential"); + pkg_formatted_field(fp, pkg, "Architecture"); + pkg_formatted_field(fp, pkg, "Maintainer"); + pkg_formatted_field(fp, pkg, "MD5sum"); + pkg_formatted_field(fp, pkg, "Size"); + pkg_formatted_field(fp, pkg, "Filename"); + pkg_formatted_field(fp, pkg, "Conffiles"); + pkg_formatted_field(fp, pkg, "Source"); + pkg_formatted_field(fp, pkg, "Description"); + pkg_formatted_field(fp, pkg, "Installed-Time"); + pkg_formatted_field(fp, pkg, "Tags"); + fputs("\n", fp); +} + +void +pkg_print_status(pkg_t * pkg, FILE * file) +{ + if (pkg == NULL) { + return; + } + + pkg_formatted_field(file, pkg, "Package"); + pkg_formatted_field(file, pkg, "Version"); + pkg_formatted_field(file, pkg, "Depends"); + pkg_formatted_field(file, pkg, "Recommends"); + pkg_formatted_field(file, pkg, "Suggests"); + pkg_formatted_field(file, pkg, "Provides"); + pkg_formatted_field(file, pkg, "Replaces"); + pkg_formatted_field(file, pkg, "Conflicts"); + pkg_formatted_field(file, pkg, "Status"); + pkg_formatted_field(file, pkg, "Essential"); + pkg_formatted_field(file, pkg, "Architecture"); + pkg_formatted_field(file, pkg, "Conffiles"); + pkg_formatted_field(file, pkg, "Installed-Time"); + pkg_formatted_field(file, pkg, "Auto-Installed"); + fputs("\n", file); +} + +/* + * libdpkg - Debian packaging suite library routines + * vercmp.c - comparison of version numbers + * + * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk> + */ + +/* assume ascii; warning: evaluates x multiple times! */ +#define order(x) ((x) == '~' ? -1 \ + : isdigit((x)) ? 0 \ + : !(x) ? 0 \ + : isalpha((x)) ? (x) \ + : (x) + 256) + +static int +verrevcmp(const char *val, const char *ref) { + if (!val) val= ""; + if (!ref) ref= ""; + + while (*val || *ref) { + int first_diff= 0; + + while ( (*val && !isdigit(*val)) || (*ref && !isdigit(*ref)) ) { + int vc= order(*val), rc= order(*ref); + if (vc != rc) return vc - rc; + val++; ref++; + } + + while ( *val == '0' ) val++; + while ( *ref == '0' ) ref++; + while (isdigit(*val) && isdigit(*ref)) { + if (!first_diff) first_diff= *val - *ref; + val++; ref++; + } + if (isdigit(*val)) return 1; + if (isdigit(*ref)) return -1; + if (first_diff) return first_diff; + } + return 0; +} + +int +pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg) +{ + int r; + + if (pkg->epoch > ref_pkg->epoch) { + return 1; + } + + if (pkg->epoch < ref_pkg->epoch) { + return -1; + } + + r = verrevcmp(pkg->version, ref_pkg->version); + if (r) { + return r; + } + + r = verrevcmp(pkg->revision, ref_pkg->revision); + if (r) { + return r; + } + + return r; +} + + +int +pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op) +{ + int r; + + r = pkg_compare_versions(it, ref); + + if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) { + return r <= 0; + } + + if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) { + return r >= 0; + } + + if (strcmp(op, "<<") == 0) { + return r < 0; + } + + if (strcmp(op, ">>") == 0) { + return r > 0; + } + + if (strcmp(op, "=") == 0) { + return r == 0; + } + + opkg_msg(ERROR, "Unknown operator: %s.\n", op); + return 0; +} + +int +pkg_name_version_and_architecture_compare(const void *p1, const void *p2) +{ + const pkg_t *a = *(const pkg_t**) p1; + const pkg_t *b = *(const pkg_t**) p2; + int namecmp; + int vercmp; + if (!a->name || !b->name) { + opkg_msg(ERROR, "Internal error: a->name=%p, b->name=%p.\n", + a->name, b->name); + return 0; + } + + namecmp = strcmp(a->name, b->name); + if (namecmp) + return namecmp; + vercmp = pkg_compare_versions(a, b); + if (vercmp) + return vercmp; + if (!a->arch_priority || !b->arch_priority) { + opkg_msg(ERROR, "Internal error: a->arch_priority=%i b->arch_priority=%i.\n", + a->arch_priority, b->arch_priority); + return 0; + } + if (a->arch_priority > b->arch_priority) + return 1; + if (a->arch_priority < b->arch_priority) + return -1; + return 0; +} + +int +abstract_pkg_name_compare(const void *p1, const void *p2) +{ + const abstract_pkg_t *a = *(const abstract_pkg_t **)p1; + const abstract_pkg_t *b = *(const abstract_pkg_t **)p2; + if (!a->name || !b->name) { + opkg_msg(ERROR, "Internal error: a->name=%p b->name=%p.\n", + a->name, b->name); + return 0; + } + return strcmp(a->name, b->name); +} + + +char * +pkg_version_str_alloc(pkg_t *pkg) +{ + char *version; + + if (pkg->epoch) { + if (pkg->revision) + sprintf_alloc(&version, "%d:%s-%s", + pkg->epoch, pkg->version, pkg->revision); + else + sprintf_alloc(&version, "%d:%s", + pkg->epoch, pkg->version); + } else { + if (pkg->revision) + sprintf_alloc(&version, "%s-%s", + pkg->version, pkg->revision); + else + version = xstrdup(pkg->version); + } + + return version; +} + +/* + * XXX: this should be broken into two functions + */ +str_list_t * +pkg_get_installed_files(pkg_t *pkg) +{ + int err, fd; + char *list_file_name = NULL; + FILE *list_file = NULL; + char *line; + char *installed_file_name; + unsigned int rootdirlen = 0; + int list_from_package; + + pkg->installed_files_ref_cnt++; + + if (pkg->installed_files) { + return pkg->installed_files; + } + + pkg->installed_files = str_list_alloc(); + + /* + * For installed packages, look at the package.list file in the database. + * For uninstalled packages, get the file list directly from the package. + */ + if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) + list_from_package = 1; + else + list_from_package = 0; + + if (list_from_package) { + if (pkg->local_filename == NULL) { + return pkg->installed_files; + } + /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary + file. In other words, change deb_extract so that it can + simply return the file list as a char *[] rather than + insisting on writing it to a FILE * as it does now. */ + sprintf_alloc(&list_file_name, "%s/%s.list.XXXXXX", + conf->tmp_dir, pkg->name); + fd = mkstemp(list_file_name); + if (fd == -1) { + opkg_perror(ERROR, "Failed to make temp file %s.", + list_file_name); + free(list_file_name); + return pkg->installed_files; + } + list_file = fdopen(fd, "r+"); + if (list_file == NULL) { + opkg_perror(ERROR, "Failed to fdopen temp file %s.", + list_file_name); + close(fd); + unlink(list_file_name); + free(list_file_name); + return pkg->installed_files; + } + err = pkg_extract_data_file_names_to_stream(pkg, list_file); + if (err) { + opkg_msg(ERROR, "Error extracting file list from %s.\n", + pkg->local_filename); + fclose(list_file); + unlink(list_file_name); + free(list_file_name); + str_list_deinit(pkg->installed_files); + pkg->installed_files = NULL; + return NULL; + } + rewind(list_file); + } else { + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + list_file = fopen(list_file_name, "r"); + if (list_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", + list_file_name); + free(list_file_name); + return pkg->installed_files; + } + free(list_file_name); + } + + if (conf->offline_root) + rootdirlen = strlen(conf->offline_root); + + while (1) { + char *file_name; + + line = file_read_line_alloc(list_file); + if (line == NULL) { + break; + } + file_name = line; + + if (list_from_package) { + if (*file_name == '.') { + file_name++; + } + if (*file_name == '/') { + file_name++; + } + sprintf_alloc(&installed_file_name, "%s%s", + pkg->dest->root_dir, file_name); + } else { + if (conf->offline_root && + strncmp(conf->offline_root, file_name, rootdirlen)) { + sprintf_alloc(&installed_file_name, "%s%s", + conf->offline_root, file_name); + } else { + // already contains root_dir as header -> ABSOLUTE + sprintf_alloc(&installed_file_name, "%s", file_name); + } + } + str_list_append(pkg->installed_files, installed_file_name); + free(installed_file_name); + free(line); + } + + fclose(list_file); + + if (list_from_package) { + unlink(list_file_name); + free(list_file_name); + } + + return pkg->installed_files; +} + +/* XXX: CLEANUP: This function and it's counterpart, + (pkg_get_installed_files), do not match our init/deinit naming + convention. Nor the alloc/free convention. But, then again, neither + of these conventions currrently fit the way these two functions + work. */ +void +pkg_free_installed_files(pkg_t *pkg) +{ + pkg->installed_files_ref_cnt--; + + if (pkg->installed_files_ref_cnt > 0) + return; + + if (pkg->installed_files) { + str_list_purge(pkg->installed_files); + } + + pkg->installed_files = NULL; +} + +void +pkg_remove_installed_files_list(pkg_t *pkg) +{ + char *list_file_name; + + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + + if (!conf->noaction) + (void)unlink(list_file_name); + + free(list_file_name); +} + +conffile_t * +pkg_get_conffile(pkg_t *pkg, const char *file_name) +{ + conffile_list_elt_t *iter; + conffile_t *conffile; + + if (pkg == NULL) { + return NULL; + } + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + conffile = (conffile_t *)iter->data; + + if (strcmp(conffile->name, file_name) == 0) { + return conffile; + } + } + + return NULL; +} + +int +pkg_run_script(pkg_t *pkg, const char *script, const char *args) +{ + int err; + char *path; + char *cmd; + + if (conf->noaction) + return 0; + + if (conf->offline_root && !conf->force_postinstall) { + opkg_msg(INFO, "Offline root mode: not running %s.%s.\n", + pkg->name, script); + return 0; + } + + /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages + have scripts in pkg->tmp_unpack_dir. */ + if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) { + if (pkg->dest == NULL) { + opkg_msg(ERROR, "Internal error: %s has a NULL dest.\n", + pkg->name); + return -1; + } + sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script); + } else { + if (pkg->tmp_unpack_dir == NULL) { + opkg_msg(ERROR, "Internal error: %s has a NULL tmp_unpack_dir.\n", + pkg->name); + return -1; + } + sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script); + } + + opkg_msg(INFO, "Running script %s.\n", path); + + setenv("PKG_ROOT", + pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1); + + if (! file_exists(path)) { + free(path); + return 0; + } + + sprintf_alloc(&cmd, "%s %s", path, args); + free(path); + { + const char *argv[] = {"sh", "-c", cmd, NULL}; + err = xsystem(argv); + } + free(cmd); + + if (err) { + opkg_msg(ERROR, "package \"%s\" %s script returned status %d.\n", + pkg->name, script, err); + return err; + } + + return 0; +} + +int +pkg_arch_supported(pkg_t *pkg) +{ + nv_pair_list_elt_t *l; + + if (!pkg->architecture) + return 1; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (strcmp(nv->name, pkg->architecture) == 0) { + opkg_msg(DEBUG, "Arch %s (priority %s) supported for pkg %s.\n", + nv->name, nv->value, pkg->name); + return 1; + } + } + + opkg_msg(DEBUG, "Arch %s unsupported for pkg %s.\n", + pkg->architecture, pkg->name); + return 0; +} + +void +pkg_info_preinstall_check(void) +{ + int i; + pkg_vec_t *installed_pkgs = pkg_vec_alloc(); + + /* update the file owner data structure */ + opkg_msg(INFO, "Updating file owner list.\n"); + pkg_hash_fetch_all_installed(installed_pkgs); + for (i = 0; i < installed_pkgs->len; i++) { + pkg_t *pkg = installed_pkgs->pkgs[i]; + str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */ + str_list_elt_t *iter, *niter; + if (installed_files == NULL) { + opkg_msg(ERROR, "Failed to determine installed " + "files for pkg %s.\n", pkg->name); + break; + } + for (iter = str_list_first(installed_files), niter = str_list_next(installed_files, iter); + iter; + iter = niter, niter = str_list_next(installed_files, iter)) { + char *installed_file = (char *) iter->data; + file_hash_set_file_owner(installed_file, pkg); + } + pkg_free_installed_files(pkg); + } + pkg_vec_free(installed_pkgs); +} + +struct pkg_write_filelist_data { + pkg_t *pkg; + FILE *stream; +}; + +static void +pkg_write_filelist_helper(const char *key, void *entry_, void *data_) +{ + struct pkg_write_filelist_data *data = data_; + pkg_t *entry = entry_; + if (entry == data->pkg) { + fprintf(data->stream, "%s\n", key); + } +} + +int +pkg_write_filelist(pkg_t *pkg) +{ + struct pkg_write_filelist_data data; + char *list_file_name; + + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + + opkg_msg(INFO, "Creating %s file for pkg %s.\n", + list_file_name, pkg->name); + + data.stream = fopen(list_file_name, "w"); + if (!data.stream) { + opkg_perror(ERROR, "Failed to open %s", + list_file_name); + free(list_file_name); + return -1; + } + + data.pkg = pkg; + hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data); + fclose(data.stream); + free(list_file_name); + + pkg->state_flag &= ~SF_FILELIST_CHANGED; + + return 0; +} + +int +pkg_write_changed_filelists(void) +{ + pkg_vec_t *installed_pkgs = pkg_vec_alloc(); + int i, err, ret = 0; + + if (conf->noaction) + return 0; + + opkg_msg(INFO, "Saving changed filelists.\n"); + + pkg_hash_fetch_all_installed(installed_pkgs); + for (i = 0; i < installed_pkgs->len; i++) { + pkg_t *pkg = installed_pkgs->pkgs[i]; + if (pkg->state_flag & SF_FILELIST_CHANGED) { + err = pkg_write_filelist(pkg); + if (err) + ret = -1; + } + } + + pkg_vec_free (installed_pkgs); + + return ret; +} diff --git a/src/libopkg/.svn/text-base/pkg.h.svn-base b/src/libopkg/.svn/text-base/pkg.h.svn-base new file mode 100644 index 0000000..775b656 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg.h.svn-base @@ -0,0 +1,231 @@ +/* pkg.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_H +#define PKG_H + +#include "config.h" + +#include <sys/types.h> + +#include "pkg_vec.h" +#include "str_list.h" +#include "active_list.h" +#include "pkg_src.h" +#include "pkg_dest.h" +#include "opkg_conf.h" +#include "conffile_list.h" + +struct opkg_conf; + + +#define ARRAY_SIZE(array) sizeof(array) / sizeof((array)[0]) + +/* I think "Size" is currently the shortest field name */ +#define PKG_MINIMUM_FIELD_NAME_LEN 4 + +enum pkg_state_want +{ + SW_UNKNOWN = 1, + SW_INSTALL, + SW_DEINSTALL, + SW_PURGE, + SW_LAST_STATE_WANT +}; +typedef enum pkg_state_want pkg_state_want_t; + +enum pkg_state_flag +{ + SF_OK = 0, + SF_REINSTREQ = 1, + SF_HOLD = 2, /* do not upgrade version */ + SF_REPLACE = 4, /* replace this package */ + SF_NOPRUNE = 8, /* do not remove obsolete files */ + SF_PREFER = 16, /* prefer this version */ + SF_OBSOLETE = 32, /* old package in upgrade pair */ + SF_MARKED = 64, /* temporary mark */ + SF_FILELIST_CHANGED = 128, /* needs filelist written */ + SF_USER = 256, + SF_LAST_STATE_FLAG +}; +typedef enum pkg_state_flag pkg_state_flag_t; +#define SF_NONVOLATILE_FLAGS (SF_HOLD|SF_NOPRUNE|SF_PREFER|SF_OBSOLETE|SF_USER) + +enum pkg_state_status +{ + SS_NOT_INSTALLED = 1, + SS_UNPACKED, + SS_HALF_CONFIGURED, + SS_INSTALLED, + SS_HALF_INSTALLED, + SS_CONFIG_FILES, + SS_POST_INST_FAILED, + SS_REMOVAL_FAILED, + SS_LAST_STATE_STATUS +}; +typedef enum pkg_state_status pkg_state_status_t; + +struct abstract_pkg{ + char * name; + int dependencies_checked; + pkg_vec_t * pkgs; + pkg_state_status_t state_status; + pkg_state_flag_t state_flag; + + /* XXX: This should be abstract_pkg_vec_t for consistency. */ + struct abstract_pkg ** depended_upon_by; + + abstract_pkg_vec_t * provided_by; + abstract_pkg_vec_t * replaced_by; +}; + +#include "pkg_depends.h" + +/* XXX: CLEANUP: I'd like to clean up pkg_t in several ways: + + The 3 version fields should go into a single version struct. (This + is especially important since, currently, pkg->version can easily + be mistaken for pkg_verson_str_alloc(pkg) although they are very + distinct. This has been the source of multiple bugs. + + The 3 state fields could possibly also go into their own struct. + + All fields which deal with lists of packages, (Depends, + Pre-Depends, Provides, Suggests, Recommends, Enhances), should each + be handled by a single struct in pkg_t + + All string fields for which there is a small set of possible + values, (section, maintainer, architecture, maybe version?), that + are reused among different packages -- for all such packages we + should move from "char *"s to some atom datatype to share data + storage and use less memory. We might even do reference counting, + but probably not since most often we only create new pkg_t structs, + we don't often free them. */ +struct pkg +{ + char *name; + unsigned long epoch; + char *version; + char *revision; + pkg_src_t *src; + pkg_dest_t *dest; + char *architecture; + char *section; + char *maintainer; + char *description; + char *tags; + pkg_state_want_t state_want; + pkg_state_flag_t state_flag; + pkg_state_status_t state_status; + char **depends_str; + unsigned int depends_count; + char **pre_depends_str; + unsigned int pre_depends_count; + char **recommends_str; + unsigned int recommends_count; + char **suggests_str; + unsigned int suggests_count; + struct active_list list; /* Used for installing|upgrading */ + compound_depend_t * depends; + + char **conflicts_str; + compound_depend_t * conflicts; + unsigned int conflicts_count; + + char **replaces_str; + unsigned int replaces_count; + abstract_pkg_t ** replaces; + + char **provides_str; + unsigned int provides_count; + abstract_pkg_t ** provides; + + abstract_pkg_t *parent; + + char *filename; + char *local_filename; + char *tmp_unpack_dir; + char *md5sum; +#if defined HAVE_SHA256 + char *sha256sum; +#endif + unsigned long size; /* in bytes */ + unsigned long installed_size; /* in bytes */ + char *priority; + char *source; + conffile_list_t conffiles; + time_t installed_time; + /* As pointer for lazy evaluation */ + str_list_t *installed_files; + /* XXX: CLEANUP: I'd like to perhaps come up with a better + mechanism to avoid the problem here, (which is that the + installed_files list was being freed from an inner loop while + still being used within an outer loop. */ + int installed_files_ref_cnt; + int essential; + int arch_priority; +/* Adding this flag, to "force" opkg to choose a "provided_by_hand" package, if there are multiple choice */ + int provided_by_hand; + + /* this flag specifies whether the package was installed to satisfy another + * package's dependancies */ + int auto_installed; +}; + +pkg_t *pkg_new(void); +void pkg_deinit(pkg_t *pkg); +int pkg_init_from_file(pkg_t *pkg, const char *filename); +abstract_pkg_t *abstract_pkg_new(void); + +/* + * merges fields from newpkg into oldpkg. + * Forcibly sets oldpkg state_status, state_want and state_flags + */ +int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg); + +char *pkg_version_str_alloc(pkg_t *pkg); + +int pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg); +int pkg_name_version_and_architecture_compare(const void *a, const void *b); +int abstract_pkg_name_compare(const void *a, const void *b); + +void pkg_formatted_info(FILE *fp, pkg_t *pkg); +void pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field); + +void set_flags_from_control(pkg_t *pkg); + +void pkg_print_status(pkg_t * pkg, FILE * file); +str_list_t *pkg_get_installed_files(pkg_t *pkg); +void pkg_free_installed_files(pkg_t *pkg); +void pkg_remove_installed_files_list(pkg_t *pkg); +conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name); +int pkg_run_script(pkg_t *pkg, const char *script, const char *args); + +/* enum mappings */ +pkg_state_want_t pkg_state_want_from_str(char *str); +pkg_state_flag_t pkg_state_flag_from_str(const char *str); +pkg_state_status_t pkg_state_status_from_str(const char *str); + +int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op); + +int pkg_arch_supported(pkg_t *pkg); +void pkg_info_preinstall_check(void); + +int pkg_write_filelist(pkg_t *pkg); +int pkg_write_changed_filelists(void); + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_depends.c.svn-base b/src/libopkg/.svn/text-base/pkg_depends.c.svn-base new file mode 100644 index 0000000..1e14d1f --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_depends.c.svn-base @@ -0,0 +1,931 @@ +/* pkg_depends.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <stdio.h> +#include <ctype.h> + +#include "pkg.h" +#include "opkg_utils.h" +#include "pkg_hash.h" +#include "opkg_message.h" +#include "pkg_parse.h" +#include "hash_table.h" +#include "libbb/libbb.h" + +static int parseDepends(compound_depend_t *compound_depend, char * depend_str); +static depend_t * depend_init(void); +static char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx); +static char ** merge_unresolved(char ** oldstuff, char ** newstuff); +static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg); + +static int pkg_installed_and_constraint_satisfied(pkg_t *pkg, void *cdata) +{ + depend_t *depend = (depend_t *)cdata; + if ((pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) && version_constraints_satisfied(depend, pkg)) + return 1; + else + return 0; +} + +static int pkg_constraint_satisfied(pkg_t *pkg, void *cdata) +{ + depend_t *depend = (depend_t *)cdata; + if (version_constraints_satisfied(depend, pkg)) + return 1; + else + return 0; +} + +/* returns ndependencies or negative error value */ +int +pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *unsatisfied, + char *** unresolved) +{ + pkg_t * satisfier_entry_pkg; + int i, j, k; + int count, found; + char ** the_lost; + abstract_pkg_t * ab_pkg; + + /* + * this is a setup to check for redundant/cyclic dependency checks, + * which are marked at the abstract_pkg level + */ + if (!(ab_pkg = pkg->parent)) { + opkg_msg(ERROR, "Internal error, with pkg %s.\n", pkg->name); + *unresolved = NULL; + return 0; + } + if (ab_pkg->dependencies_checked) { /* avoid duplicate or cyclic checks */ + *unresolved = NULL; + return 0; + } else { + ab_pkg->dependencies_checked = 1; /* mark it for subsequent visits */ + } + /**/ + + count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count; + if (!count){ + *unresolved = NULL; + return 0; + } + + the_lost = NULL; + + /* foreach dependency */ + for (i = 0; i < count; i++) { + compound_depend_t * compound_depend = &pkg->depends[i]; + depend_t ** possible_satisfiers = compound_depend->possibilities;; + found = 0; + satisfier_entry_pkg = NULL; + + if (compound_depend->type == GREEDY_DEPEND) { + /* foreach possible satisfier */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + abstract_pkg_t *abpkg = possible_satisfiers[j]->pkg; + abstract_pkg_vec_t *ab_provider_vec = abpkg->provided_by; + int nposs = ab_provider_vec->len; + abstract_pkg_t **ab_providers = ab_provider_vec->pkgs; + int l; + for (l = 0; l < nposs; l++) { + pkg_vec_t *test_vec = ab_providers[l]->pkgs; + /* if no depends on this one, try the first package that Provides this one */ + if (!test_vec){ /* no pkg_vec hooked up to the abstract_pkg! (need another feed?) */ + continue; + } + + /* cruise this possiblity's pkg_vec looking for an installed version */ + for (k = 0; k < test_vec->len; k++) { + pkg_t *pkg_scout = test_vec->pkgs[k]; + /* not installed, and not already known about? */ + if ((pkg_scout->state_want != SW_INSTALL) + && !pkg_scout->parent->dependencies_checked + && !is_pkg_in_pkg_vec(unsatisfied, pkg_scout)) { + char ** newstuff = NULL; + int rc; + pkg_vec_t *tmp_vec = pkg_vec_alloc (); + /* check for not-already-installed dependencies */ + rc = pkg_hash_fetch_unsatisfied_dependencies(pkg_scout, + tmp_vec, + &newstuff); + if (newstuff == NULL) { + int m; + int ok = 1; + for (m = 0; m < rc; m++) { + pkg_t *p = tmp_vec->pkgs[m]; + if (p->state_want == SW_INSTALL) + continue; + opkg_msg(DEBUG, + "Not installing %s due" + " to requirement for %s.\n", + pkg_scout->name, + p->name); + ok = 0; + break; + } + pkg_vec_free (tmp_vec); + if (ok) { + /* mark this one for installation */ + opkg_msg(NOTICE, + "Adding satisfier for greedy" + " dependence %s.\n", + pkg_scout->name); + pkg_vec_insert(unsatisfied, pkg_scout); + } + } else { + opkg_msg(DEBUG, + "Not installing %s due to " + "broken depends.\n", + pkg_scout->name); + free (newstuff); + } + } + } + } + } + + continue; + } + + /* foreach possible satisfier, look for installed package */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + depend_t *dependence_to_satisfy = possible_satisfiers[j]; + abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg; + pkg_t *satisfying_pkg = + pkg_hash_fetch_best_installation_candidate(satisfying_apkg, + pkg_installed_and_constraint_satisfied, + dependence_to_satisfy, 1); + /* Being that I can't test constraing in pkg_hash, I will test it here */ + if (satisfying_pkg != NULL) { + if (!pkg_installed_and_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) { + satisfying_pkg = NULL; + } + } + opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg); + if (satisfying_pkg != NULL) { + found = 1; + break; + } + + } + /* if nothing installed matches, then look for uninstalled satisfier */ + if (!found) { + /* foreach possible satisfier, look for installed package */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + depend_t *dependence_to_satisfy = possible_satisfiers[j]; + abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg; + pkg_t *satisfying_pkg = + pkg_hash_fetch_best_installation_candidate(satisfying_apkg, + pkg_constraint_satisfied, + dependence_to_satisfy, 1); + /* Being that I can't test constraing in pkg_hash, I will test it here too */ + if (satisfying_pkg != NULL) { + if (!pkg_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) { + satisfying_pkg = NULL; + } + } + + /* user request overrides package recommendation */ + if (satisfying_pkg != NULL + && (compound_depend->type == RECOMMEND || compound_depend->type == SUGGEST) + && (satisfying_pkg->state_want == SW_DEINSTALL || satisfying_pkg->state_want == SW_PURGE)) { + opkg_msg(NOTICE, "%s: ignoring recommendation for " + "%s at user request\n", + pkg->name, satisfying_pkg->name); + continue; + } + + opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg); + if (satisfying_pkg != NULL) { + satisfier_entry_pkg = satisfying_pkg; + break; + } + } + } + + /* we didn't find one, add something to the unsatisfied vector */ + if (!found) { + if (!satisfier_entry_pkg) { + /* failure to meet recommendations is not an error */ + if (compound_depend->type != RECOMMEND && compound_depend->type != SUGGEST) + the_lost = add_unresolved_dep(pkg, the_lost, i); + else + opkg_msg(NOTICE, + "%s: unsatisfied recommendation for %s\n", + pkg->name, + compound_depend->possibilities[0]->pkg->name); + } + else { + if (compound_depend->type == SUGGEST) { + /* just mention it politely */ + opkg_msg(NOTICE, "package %s suggests installing %s\n", + pkg->name, satisfier_entry_pkg->name); + } else { + char ** newstuff = NULL; + + if (satisfier_entry_pkg != pkg && + !is_pkg_in_pkg_vec(unsatisfied, satisfier_entry_pkg)) { + pkg_vec_insert(unsatisfied, satisfier_entry_pkg); + pkg_hash_fetch_unsatisfied_dependencies(satisfier_entry_pkg, + unsatisfied, + &newstuff); + the_lost = merge_unresolved(the_lost, newstuff); + if (newstuff) + free(newstuff); + } + } + } + } + } + *unresolved = the_lost; + + return unsatisfied->len; +} + +/*checking for conflicts !in replaces + If a packages conflicts with another but is also replacing it, I should not consider it a + really conflicts + returns 0 if conflicts <> replaces or 1 if conflicts == replaces +*/ +static int +is_pkg_a_replaces(pkg_t *pkg_scout,pkg_t *pkg) +{ + int i ; + int replaces_count = pkg->replaces_count; + abstract_pkg_t **replaces; + + if (pkg->replaces_count==0) // No replaces, it's surely a conflict + return 0; + + replaces = pkg->replaces; + + for (i = 0; i < replaces_count; i++) { + if (strcmp(pkg_scout->name,pkg->replaces[i]->name)==0) { // Found + opkg_msg(DEBUG2, "Seems I've found a replace %s %s\n", + pkg_scout->name, pkg->replaces[i]->name); + return 1; + } + } + return 0; + +} + + +pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg) +{ + pkg_vec_t * installed_conflicts, * test_vec; + compound_depend_t * conflicts; + depend_t ** possible_satisfiers; + depend_t * possible_satisfier; + int i, j, k; + int count; + abstract_pkg_t * ab_pkg; + pkg_t **pkg_scouts; + pkg_t *pkg_scout; + + /* + * this is a setup to check for redundant/cyclic dependency checks, + * which are marked at the abstract_pkg level + */ + if(!(ab_pkg = pkg->parent)){ + opkg_msg(ERROR, "Internal error: %s not in hash table\n", pkg->name); + return (pkg_vec_t *)NULL; + } + + conflicts = pkg->conflicts; + if(!conflicts){ + return (pkg_vec_t *)NULL; + } + installed_conflicts = pkg_vec_alloc(); + + count = pkg->conflicts_count; + + + + /* foreach conflict */ + for(i = 0; i < pkg->conflicts_count; i++){ + + possible_satisfiers = conflicts->possibilities; + + /* foreach possible satisfier */ + for(j = 0; j < conflicts->possibility_count; j++){ + possible_satisfier = possible_satisfiers[j]; + if (!possible_satisfier) + opkg_msg(ERROR, "Internal error: possible_satisfier=NULL\n"); + if (!possible_satisfier->pkg) + opkg_msg(ERROR, "Internal error: possible_satisfier->pkg=NULL\n"); + test_vec = possible_satisfier->pkg->pkgs; + if (test_vec) { + /* pkg_vec found, it is an actual package conflict + * cruise this possiblity's pkg_vec looking for an installed version */ + pkg_scouts = test_vec->pkgs; + for(k = 0; k < test_vec->len; k++){ + pkg_scout = pkg_scouts[k]; + if (!pkg_scout) { + opkg_msg(ERROR, "Internal error: pkg_scout=NULL\n"); + continue; + } + if ((pkg_scout->state_status == SS_INSTALLED || pkg_scout->state_want == SW_INSTALL) && + version_constraints_satisfied(possible_satisfier, pkg_scout) && !is_pkg_a_replaces(pkg_scout,pkg)){ + if (!is_pkg_in_pkg_vec(installed_conflicts, pkg_scout)){ + pkg_vec_insert(installed_conflicts, pkg_scout); + } + } + } + } + } + conflicts++; + } + + if (installed_conflicts->len) + return installed_conflicts; + pkg_vec_free(installed_conflicts); + return (pkg_vec_t *)NULL; +} + +int version_constraints_satisfied(depend_t * depends, pkg_t * pkg) +{ + pkg_t * temp; + int comparison; + + if(depends->constraint == NONE) + return 1; + + temp = pkg_new(); + + parse_version(temp, depends->version); + + comparison = pkg_compare_versions(pkg, temp); + + free (temp->version); + free(temp); + + if((depends->constraint == EARLIER) && + (comparison < 0)) + return 1; + else if((depends->constraint == LATER) && + (comparison > 0)) + return 1; + else if(comparison == 0) + return 1; + else if((depends->constraint == LATER_EQUAL) && + (comparison >= 0)) + return 1; + else if((depends->constraint == EARLIER_EQUAL) && + (comparison <= 0)) + return 1; + + return 0; +} + +int pkg_dependence_satisfiable(depend_t *depend) +{ + abstract_pkg_t *apkg = depend->pkg; + abstract_pkg_vec_t *provider_apkgs = apkg->provided_by; + int n_providers = provider_apkgs->len; + abstract_pkg_t **apkgs = provider_apkgs->pkgs; + pkg_vec_t *pkg_vec; + int n_pkgs ; + int i; + int j; + + for (i = 0; i < n_providers; i++) { + abstract_pkg_t *papkg = apkgs[i]; + pkg_vec = papkg->pkgs; + if (pkg_vec) { + n_pkgs = pkg_vec->len; + for (j = 0; j < n_pkgs; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (version_constraints_satisfied(depend, pkg)) { + return 1; + } + } + } + } + return 0; +} + +int pkg_dependence_satisfied(depend_t *depend) +{ + abstract_pkg_t *apkg = depend->pkg; + abstract_pkg_vec_t *provider_apkgs = apkg->provided_by; + int n_providers = provider_apkgs->len; + abstract_pkg_t **apkgs = provider_apkgs->pkgs; + int i; + int n_pkgs; + int j; + + for (i = 0; i < n_providers; i++) { + abstract_pkg_t *papkg = apkgs[i]; + pkg_vec_t *pkg_vec = papkg->pkgs; + if (pkg_vec) { + n_pkgs = pkg_vec->len; + for (j = 0; j < n_pkgs; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (version_constraints_satisfied(depend, pkg)) { + if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) + return 1; + } + } + } + } + return 0; +} + +static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg) +{ + int i; + pkg_t ** pkgs = vec->pkgs; + + for(i = 0; i < vec->len; i++) + if((strcmp(pkg->name, (*(pkgs + i))->name) == 0) + && (pkg_compare_versions(pkg, *(pkgs + i)) == 0) + && (strcmp(pkg->architecture, (*(pkgs + i))->architecture) == 0)) + return 1; + return 0; +} + +/** + * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0 + * otherwise. + */ +int pkg_replaces(pkg_t *pkg, pkg_t *replacee) +{ + abstract_pkg_t **replaces = pkg->replaces; + int replaces_count = pkg->replaces_count; + int replacee_provides_count = replacee->provides_count; + int i, j; + for (i = 0; i < replaces_count; i++) { + abstract_pkg_t *abstract_replacee = replaces[i]; + for (j = 0; j < replacee_provides_count; j++) { + if (replacee->provides[j] == abstract_replacee) + return 1; + } + } + return 0; +} + + +/** + * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee and 0 + * otherwise. + */ +int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflictee) +{ + compound_depend_t *conflicts = pkg->conflicts; + int conflicts_count = pkg->conflicts_count; + int i, j; + for (i = 0; i < conflicts_count; i++) { + int possibility_count = conflicts[i].possibility_count; + struct depend **possibilities = conflicts[i].possibilities; + for (j = 0; j < possibility_count; j++) { + if (possibilities[j]->pkg == conflictee) { + return 1; + } + } + } + return 0; +} + +/** + * pkg_conflicts returns 1 if pkg->conflicts contains one of + * conflictee's provides and 0 otherwise. + */ +int pkg_conflicts(pkg_t *pkg, pkg_t *conflictee) +{ + compound_depend_t *conflicts = pkg->conflicts; + int conflicts_count = pkg->conflicts_count; + abstract_pkg_t **conflictee_provides = conflictee->provides; + int conflictee_provides_count = conflictee->provides_count; + int i, j, k; + int possibility_count; + struct depend **possibilities; + abstract_pkg_t *possibility ; + + for (i = 0; i < conflicts_count; i++) { + possibility_count = conflicts[i].possibility_count; + possibilities = conflicts[i].possibilities; + for (j = 0; j < possibility_count; j++) { + possibility = possibilities[j]->pkg; + for (k = 0; k < conflictee_provides_count; k++) { + if (possibility == conflictee_provides[k]) { + return 1; + } + } + } + } + return 0; +} + +static char ** merge_unresolved(char ** oldstuff, char ** newstuff) +{ + int oldlen = 0, newlen = 0; + char ** result; + int i, j; + + if(!newstuff) + return oldstuff; + + while(oldstuff && oldstuff[oldlen]) oldlen++; + while(newstuff && newstuff[newlen]) newlen++; + + result = xrealloc(oldstuff, sizeof(char *) * (oldlen + newlen + 1)); + + for(i = oldlen, j = 0; i < (oldlen + newlen); i++, j++) + *(result + i) = *(newstuff + j); + + *(result + i) = NULL; + + return result; +} + +/* + * a kinda kludgy way to back out depends str from two different arrays (reg'l'r 'n pre) + * this is null terminated, no count is carried around + */ +char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx) +{ + int count; + char ** resized; + + count = 0; + while(the_lost && the_lost[count]) count++; + + count++; /* need one to hold the null */ + resized = xrealloc(the_lost, sizeof(char *) * (count + 1)); + resized[count - 1] = pkg_depend_str(pkg, ref_ndx); + resized[count] = NULL; + + return resized; +} + +void buildProvides(abstract_pkg_t * ab_pkg, pkg_t * pkg) +{ + int i; + + /* every pkg provides itself */ + pkg->provides_count++; + abstract_pkg_vec_insert(ab_pkg->provided_by, ab_pkg); + pkg->provides = xcalloc(pkg->provides_count, sizeof(abstract_pkg_t *)); + pkg->provides[0] = ab_pkg; + + for (i=1; i<pkg->provides_count; i++) { + abstract_pkg_t *provided_abpkg = ensure_abstract_pkg_by_name( + pkg->provides_str[i-1]); + free(pkg->provides_str[i-1]); + + pkg->provides[i] = provided_abpkg; + + abstract_pkg_vec_insert(provided_abpkg->provided_by, ab_pkg); + } + if (pkg->provides_str) + free(pkg->provides_str); +} + +void buildConflicts(pkg_t * pkg) +{ + int i; + compound_depend_t * conflicts; + + if (!pkg->conflicts_count) + return; + + conflicts = pkg->conflicts = xcalloc(pkg->conflicts_count, sizeof(compound_depend_t)); + for (i = 0; i < pkg->conflicts_count; i++) { + conflicts->type = CONFLICTS; + parseDepends(conflicts, pkg->conflicts_str[i]); + free(pkg->conflicts_str[i]); + conflicts++; + } + if (pkg->conflicts_str) + free(pkg->conflicts_str); +} + +void buildReplaces(abstract_pkg_t * ab_pkg, pkg_t * pkg) +{ + int i; + + if (!pkg->replaces_count) + return; + + pkg->replaces = xcalloc(pkg->replaces_count, sizeof(abstract_pkg_t *)); + + for(i = 0; i < pkg->replaces_count; i++){ + abstract_pkg_t *old_abpkg = ensure_abstract_pkg_by_name(pkg->replaces_str[i]); + + pkg->replaces[i] = old_abpkg; + free(pkg->replaces_str[i]); + + if (!old_abpkg->replaced_by) + old_abpkg->replaced_by = abstract_pkg_vec_alloc(); + /* if a package pkg both replaces and conflicts old_abpkg, + * then add it to the replaced_by vector so that old_abpkg + * will be upgraded to ab_pkg automatically */ + if (pkg_conflicts_abstract(pkg, old_abpkg)) + abstract_pkg_vec_insert(old_abpkg->replaced_by, ab_pkg); + } + + if (pkg->replaces_str) + free(pkg->replaces_str); +} + +void buildDepends(pkg_t * pkg) +{ + unsigned int count; + int i; + compound_depend_t * depends; + + if(!(count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count)) + return; + + depends = pkg->depends = xcalloc(count, sizeof(compound_depend_t)); + + for(i = 0; i < pkg->pre_depends_count; i++){ + parseDepends(depends, pkg->pre_depends_str[i]); + free(pkg->pre_depends_str[i]); + depends->type = PREDEPEND; + depends++; + } + if (pkg->pre_depends_str) + free(pkg->pre_depends_str); + + for(i = 0; i < pkg->depends_count; i++){ + parseDepends(depends, pkg->depends_str[i]); + free(pkg->depends_str[i]); + depends++; + } + if (pkg->depends_str) + free(pkg->depends_str); + + for(i = 0; i < pkg->recommends_count; i++){ + parseDepends(depends, pkg->recommends_str[i]); + free(pkg->recommends_str[i]); + depends->type = RECOMMEND; + depends++; + } + if(pkg->recommends_str) + free(pkg->recommends_str); + + for(i = 0; i < pkg->suggests_count; i++){ + parseDepends(depends, pkg->suggests_str[i]); + free(pkg->suggests_str[i]); + depends->type = SUGGEST; + depends++; + } + if(pkg->suggests_str) + free(pkg->suggests_str); +} + +const char* +constraint_to_str(enum version_constraint c) +{ + switch (c) { + case NONE: + return ""; + case EARLIER: + return "< "; + case EARLIER_EQUAL: + return "<= "; + case EQUAL: + return "= "; + case LATER_EQUAL: + return ">= "; + case LATER: + return "> "; + } + + return ""; +} + +/* + * Returns a printable string for pkg's dependency at the specified idx. The + * resultant string must be passed to free() by the caller. + */ +char * +pkg_depend_str(pkg_t *pkg, int idx) +{ + int i; + unsigned int len; + char *str; + compound_depend_t *cdep; + depend_t *dep; + + len = 0; + cdep = &pkg->depends[idx]; + + /* calculate string length */ + for (i=0; i<cdep->possibility_count; i++) { + dep = cdep->possibilities[i]; + + if (i != 0) + len += 3; /* space, pipe, space */ + + len += strlen(dep->pkg->name); + + if (dep->version) { + len += 2; /* space, left parenthesis */ + len += 3; /* constraint string (<=, >=, etc), space */ + len += strlen(dep->version); + len += 1; /* right parenthesis */ + } + } + + str = xmalloc(len + 1); /* +1 for the NULL terminator */ + str[0] = '\0'; + + for (i=0; i<cdep->possibility_count; i++) { + dep = cdep->possibilities[i]; + + if (i != 0) + strncat(str, " | ", len); + + strncat(str, dep->pkg->name, len); + + if (dep->version) { + strncat(str, " (", len); + strncat(str, constraint_to_str(dep->constraint), len); + strncat(str, dep->version, len); + strncat(str, ")", len); + } + } + + return str; +} + +void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg) +{ + compound_depend_t * depends; + int count, othercount; + int i, j; + abstract_pkg_t * ab_depend; + abstract_pkg_t ** temp; + + count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i = 0; i < count; i++) { + depends = &pkg->depends[i]; + if (depends->type != PREDEPEND + && depends->type != DEPEND + && depends->type != RECOMMEND) + continue; + for (j = 0; j < depends->possibility_count; j++) { + ab_depend = depends->possibilities[j]->pkg; + if (!ab_depend->depended_upon_by) { + ab_depend->depended_upon_by = + xcalloc(1, sizeof(abstract_pkg_t *)); + } + + temp = ab_depend->depended_upon_by; + othercount = 1; + while (*temp) { + temp++; + othercount++; + } + *temp = ab_pkg; + + ab_depend->depended_upon_by = + xrealloc(ab_depend->depended_upon_by, + (othercount + 1) * sizeof(abstract_pkg_t *)); + + /* the array may have been moved by realloc */ + temp = ab_depend->depended_upon_by + othercount; + *temp = NULL; + } + } +} + +static depend_t * depend_init(void) +{ + depend_t * d = xcalloc(1, sizeof(depend_t)); + d->constraint = NONE; + d->version = NULL; + d->pkg = NULL; + + return d; +} + +static int parseDepends(compound_depend_t *compound_depend, + char * depend_str) +{ + char * pkg_name, buffer[2048]; + unsigned int num_of_ors = 0; + int i; + char * src, * dest; + depend_t ** possibilities; + + /* first count the number of ored possibilities for satisfying dependency */ + src = depend_str; + while(*src) + if(*src++ == '|') + num_of_ors++; + + compound_depend->type = DEPEND; + + compound_depend->possibility_count = num_of_ors + 1; + possibilities = xcalloc((num_of_ors + 1), sizeof(depend_t *) ); + compound_depend->possibilities = possibilities; + + src = depend_str; + for(i = 0; i < num_of_ors + 1; i++){ + possibilities[i] = depend_init(); + /* gobble up just the name first */ + dest = buffer; + while(*src && + !isspace(*src) && + (*src != '(') && + (*src != '*') && + (*src != '|')) + *dest++ = *src++; + *dest = '\0'; + pkg_name = trim_xstrdup(buffer); + + /* now look at possible version info */ + + /* skip to next chars */ + if(isspace(*src)) + while(*src && isspace(*src)) src++; + + /* extract constraint and version */ + if(*src == '('){ + src++; + if(!strncmp(src, "<<", 2)){ + possibilities[i]->constraint = EARLIER; + src += 2; + } + else if(!strncmp(src, "<=", 2)){ + possibilities[i]->constraint = EARLIER_EQUAL; + src += 2; + } + else if(!strncmp(src, ">=", 2)){ + possibilities[i]->constraint = LATER_EQUAL; + src += 2; + } + else if(!strncmp(src, ">>", 2)){ + possibilities[i]->constraint = LATER; + src += 2; + } + else if(!strncmp(src, "=", 1)){ + possibilities[i]->constraint = EQUAL; + src++; + } + /* should these be here to support deprecated designations; dpkg does */ + else if(!strncmp(src, "<", 1)){ + possibilities[i]->constraint = EARLIER_EQUAL; + src++; + } + else if(!strncmp(src, ">", 1)){ + possibilities[i]->constraint = LATER_EQUAL; + src++; + } + + /* now we have any constraint, pass space to version string */ + while(isspace(*src)) src++; + + /* this would be the version string */ + dest = buffer; + while(*src && *src != ')') + *dest++ = *src++; + *dest = '\0'; + + possibilities[i]->version = trim_xstrdup(buffer); + } + /* hook up the dependency to its abstract pkg */ + possibilities[i]->pkg = ensure_abstract_pkg_by_name(pkg_name); + + free(pkg_name); + + /* now get past the ) and any possible | chars */ + while(*src && + (isspace(*src) || + (*src == ')') || + (*src == '|'))) + src++; + if (*src == '*') + { + compound_depend->type = GREEDY_DEPEND; + src++; + } + } + + return 0; +} diff --git a/src/libopkg/.svn/text-base/pkg_depends.h.svn-base b/src/libopkg/.svn/text-base/pkg_depends.h.svn-base new file mode 100644 index 0000000..5d1f074 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_depends.h.svn-base @@ -0,0 +1,90 @@ +/* pkg_depends.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PKG_DEPENDS_H +#define PKG_DEPENDS_H + +#include "pkg.h" +#include "pkg_hash.h" + +enum depend_type { + PREDEPEND, + DEPEND, + CONFLICTS, + GREEDY_DEPEND, + RECOMMEND, + SUGGEST +}; +typedef enum depend_type depend_type_t; + +enum version_constraint { + NONE, + EARLIER, + EARLIER_EQUAL, + EQUAL, + LATER_EQUAL, + LATER +}; +typedef enum version_constraint version_constraint_t; + +struct depend{ + version_constraint_t constraint; + char * version; + abstract_pkg_t * pkg; +}; +typedef struct depend depend_t; + +struct compound_depend{ + depend_type_t type; + int possibility_count; + struct depend ** possibilities; +}; +typedef struct compound_depend compound_depend_t; + +void buildProvides(abstract_pkg_t * ab_pkg, pkg_t * pkg); +void buildConflicts(pkg_t * pkg); +void buildReplaces(abstract_pkg_t * ab_pkg, pkg_t * pkg); +void buildDepends(pkg_t * pkg); + +/** + * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0 + * otherwise. + */ +int pkg_replaces(pkg_t *pkg, pkg_t *replacee); + +/** + * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee provides and 0 + * otherwise. + */ +int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflicts); + +/** + * pkg_conflicts returns 1 if pkg->conflicts contains one of conflictee's provides and 0 + * otherwise. + */ +int pkg_conflicts(pkg_t *pkg, pkg_t *conflicts); + +char *pkg_depend_str(pkg_t *pkg, int index); +void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg); +int version_constraints_satisfied(depend_t * depends, pkg_t * pkg); +int pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *depends, char *** unresolved); +pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg); +int pkg_dependence_satisfiable(depend_t *depend); +int pkg_dependence_satisfied(depend_t *depend); +const char* constraint_to_str(enum version_constraint c); + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_dest.c.svn-base b/src/libopkg/.svn/text-base/pkg_dest.c.svn-base new file mode 100644 index 0000000..d56dd78 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_dest.c.svn-base @@ -0,0 +1,82 @@ +/* pkg_dest.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> + +#include "pkg_dest.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char * lists_dir) +{ + dest->name = xstrdup(name); + + /* Guarantee that dest->root_dir ends with a '/' */ + if (root_dir[strlen(root_dir) -1] == '/') { + dest->root_dir = xstrdup(root_dir); + } else { + sprintf_alloc(&dest->root_dir, "%s/", root_dir); + } + file_mkdir_hier(dest->root_dir, 0755); + + sprintf_alloc(&dest->opkg_dir, "%s%s", + dest->root_dir, OPKG_STATE_DIR_PREFIX); + file_mkdir_hier(dest->opkg_dir, 0755); + + if (lists_dir[0] == '/') + sprintf_alloc(&dest->lists_dir, "%s", lists_dir); + else + sprintf_alloc(&dest->lists_dir, "/%s", lists_dir); + + file_mkdir_hier(dest->lists_dir, 0755); + + sprintf_alloc(&dest->info_dir, "%s/%s", + dest->opkg_dir, OPKG_INFO_DIR_SUFFIX); + file_mkdir_hier(dest->info_dir, 0755); + + sprintf_alloc(&dest->status_file_name, "%s/%s", + dest->opkg_dir, OPKG_STATUS_FILE_SUFFIX); + + return 0; +} + +void pkg_dest_deinit(pkg_dest_t *dest) +{ + free(dest->name); + dest->name = NULL; + + free(dest->root_dir); + dest->root_dir = NULL; + + free(dest->opkg_dir); + dest->opkg_dir = NULL; + + free(dest->lists_dir); + dest->lists_dir = NULL; + + free(dest->info_dir); + dest->info_dir = NULL; + + free(dest->status_file_name); + dest->status_file_name = NULL; + + dest->root_dir = NULL; +} diff --git a/src/libopkg/.svn/text-base/pkg_dest.h.svn-base b/src/libopkg/.svn/text-base/pkg_dest.h.svn-base new file mode 100644 index 0000000..4ad417e --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_dest.h.svn-base @@ -0,0 +1,39 @@ +/* pkg_dest.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_DEST_H +#define PKG_DEST_H + +#include <stdio.h> + +typedef struct pkg_dest pkg_dest_t; +struct pkg_dest +{ + char *name; + char *root_dir; + char *opkg_dir; + char *lists_dir; + char *info_dir; + char *status_file_name; + FILE *status_fp; +}; + +int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char *lists_dir); +void pkg_dest_deinit(pkg_dest_t *dest); + +#endif + diff --git a/src/libopkg/.svn/text-base/pkg_dest_list.c.svn-base b/src/libopkg/.svn/text-base/pkg_dest_list.c.svn-base new file mode 100644 index 0000000..f5f2e1d --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_dest_list.c.svn-base @@ -0,0 +1,77 @@ +/* pkg_dest_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> + +#include "pkg_dest.h" +#include "void_list.h" +#include "pkg_dest_list.h" +#include "libbb/libbb.h" + +void pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data) +{ + void_list_elt_init((void_list_elt_t *) elt, data); +} + +void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt) +{ + void_list_elt_deinit((void_list_elt_t *) elt); +} + +void pkg_dest_list_init(pkg_dest_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void pkg_dest_list_deinit(pkg_dest_list_t *list) +{ + pkg_dest_list_elt_t *iter, *n; + pkg_dest_t *pkg_dest; + + list_for_each_entry_safe(iter, n, &list->head, node) { + pkg_dest = (pkg_dest_t *)iter->data; + pkg_dest_deinit(pkg_dest); + + /* malloced in pkg_dest_list_append */ + free(pkg_dest); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name, + const char *root_dir,const char *lists_dir) +{ + pkg_dest_t *pkg_dest; + + /* freed in pkg_dest_list_deinit */ + pkg_dest = xcalloc(1, sizeof(pkg_dest_t)); + pkg_dest_init(pkg_dest, name, root_dir,lists_dir); + void_list_append((void_list_t *) list, pkg_dest); + + return pkg_dest; +} + +void pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list) +{ + return (pkg_dest_list_elt_t *) void_list_pop((void_list_t *) list); +} diff --git a/src/libopkg/.svn/text-base/pkg_dest_list.h.svn-base b/src/libopkg/.svn/text-base/pkg_dest_list.h.svn-base new file mode 100644 index 0000000..33aef19 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_dest_list.h.svn-base @@ -0,0 +1,39 @@ +/* pkg_dest_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_DEST_LIST_H +#define PKG_DEST_LIST_H + +#include "pkg_dest.h" + +typedef struct void_list_elt pkg_dest_list_elt_t; + +typedef struct void_list pkg_dest_list_t; + +void pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data); +void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt); + +void pkg_dest_list_init(pkg_dest_list_t *list); +void pkg_dest_list_deinit(pkg_dest_list_t *list); + +pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name, + const char *root_dir,const char* lists_dir); +void pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data); +pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list); + +#endif + diff --git a/src/libopkg/.svn/text-base/pkg_extract.c.svn-base b/src/libopkg/.svn/text-base/pkg_extract.c.svn-base new file mode 100644 index 0000000..0f21e40 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_extract.c.svn-base @@ -0,0 +1,99 @@ +/* pkg_extract.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> + +#include "pkg_extract.h" +#include "libbb/libbb.h" +#include "file_util.h" +#include "sprintf_alloc.h" + +int +pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream) +{ + int err; + deb_extract(pkg->local_filename, stream, + extract_control_tar_gz + | extract_to_stream, + NULL, "control", &err); + return err; +} + +int +pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg, const char *dir, + const char *prefix) +{ + int err; + char *dir_with_prefix; + + sprintf_alloc(&dir_with_prefix, "%s/%s", dir, prefix); + + deb_extract(pkg->local_filename, stderr, + extract_control_tar_gz + | extract_all_to_fs| extract_preserve_date + | extract_unconditional, + dir_with_prefix, NULL, &err); + + free(dir_with_prefix); + return err; +} + +int +pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir) +{ + return pkg_extract_control_files_to_dir_with_prefix(pkg, dir, ""); +} + + +int +pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir) +{ + int err; + + deb_extract(pkg->local_filename, stderr, + extract_data_tar_gz + | extract_all_to_fs| extract_preserve_date + | extract_unconditional, + dir, NULL, &err); + + return err; +} + +int +pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *stream) +{ + int err; + + /* XXX: DPKG_INCOMPATIBILITY: deb_extract will extract all of the + data file names with a '.' as the first character. I've taught + opkg how to cope with the presence or absence of the '.', but + this may trip up dpkg. + + For all I know, this could actually be a bug in opkg-build. So, + I'll have to try installing some .debs and comparing the *.list + files. + + If we wanted to, we could workaround the deb_extract behavior + right here, by writing to a tmpfile, then munging things as we + wrote to the actual stream. */ + + deb_extract(pkg->local_filename, stream, + extract_quiet | extract_data_tar_gz | extract_list, + NULL, NULL, &err); + + return err; +} diff --git a/src/libopkg/.svn/text-base/pkg_extract.h.svn-base b/src/libopkg/.svn/text-base/pkg_extract.h.svn-base new file mode 100644 index 0000000..b83b41b --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_extract.h.svn-base @@ -0,0 +1,31 @@ +/* pkg_extract.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_EXTRACT_H +#define PKG_EXTRACT_H + +#include "pkg.h" + +int pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream); +int pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir); +int pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg, + const char *dir, + const char *prefix); +int pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir); +int pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *file); + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_hash.c.svn-base b/src/libopkg/.svn/text-base/pkg_hash.c.svn-base new file mode 100644 index 0000000..a99cf6b --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_hash.c.svn-base @@ -0,0 +1,735 @@ +/* opkg_hash.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <stdio.h> + +#include "hash_table.h" +#include "release.h" +#include "pkg.h" +#include "opkg_message.h" +#include "pkg_vec.h" +#include "pkg_hash.h" +#include "parse_util.h" +#include "pkg_parse.h" +#include "opkg_utils.h" +#include "sprintf_alloc.h" +#include "file_util.h" +#include "libbb/libbb.h" + +void +pkg_hash_init(void) +{ + hash_table_init("pkg-hash", &conf->pkg_hash, + OPKG_CONF_DEFAULT_HASH_LEN); +} + +static void +free_pkgs(const char *key, void *entry, void *data) +{ + int i; + abstract_pkg_t *ab_pkg; + + /* Each entry in the hash table is an abstract package, which contains + * a list of packages that provide the abstract package. + */ + + ab_pkg = (abstract_pkg_t*) entry; + + if (ab_pkg->pkgs) { + for (i = 0; i < ab_pkg->pkgs->len; i++) { + pkg_deinit (ab_pkg->pkgs->pkgs[i]); + free (ab_pkg->pkgs->pkgs[i]); + } + } + + abstract_pkg_vec_free (ab_pkg->provided_by); + abstract_pkg_vec_free (ab_pkg->replaced_by); + pkg_vec_free (ab_pkg->pkgs); + free (ab_pkg->depended_upon_by); + free (ab_pkg->name); + free (ab_pkg); +} + +void +pkg_hash_deinit(void) +{ + hash_table_foreach(&conf->pkg_hash, free_pkgs, NULL); + hash_table_deinit(&conf->pkg_hash); +} + +int +dist_hash_add_from_file(const char *lists_dir, pkg_src_t *dist) +{ + nv_pair_list_elt_t *l; + char *list_file, *subname; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + sprintf_alloc(&subname, "%s-%s", dist->name, nv->name); + sprintf_alloc(&list_file, "%s/%s", lists_dir, subname); + + if (file_exists(list_file)) { + if (pkg_hash_add_from_file(list_file, dist, NULL, 0)) { + free(list_file); + return -1; + } + pkg_src_list_append (&conf->pkg_src_list, subname, dist->value, "__dummy__", 0); + } + + free(list_file); + } + + return 0; +} + + +int +pkg_hash_add_from_file(const char *file_name, + pkg_src_t *src, pkg_dest_t *dest, int is_status_file) +{ + pkg_t *pkg; + FILE *fp; + char *buf; + const size_t len = 4096; + int ret = 0; + + fp = fopen(file_name, "r"); + if (fp == NULL) { + opkg_perror(ERROR, "Failed to open %s", file_name); + return -1; + } + + buf = xmalloc(len); + + do { + pkg = pkg_new(); + pkg->src = src; + pkg->dest = dest; + + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, 0, + &buf, len); + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + if (ret) { + pkg_deinit (pkg); + free(pkg); + if (ret == -1) + break; + if (ret == 1) + /* Probably a blank line, continue parsing. */ + ret = 0; + continue; + } + + if (!pkg->architecture || !pkg->arch_priority) { + char *version_str = pkg_version_str_alloc(pkg); + opkg_msg(NOTICE, "Package %s version %s has no " + "valid architecture, ignoring.\n", + pkg->name, version_str); + free(version_str); + continue; + } + + hash_insert_pkg(pkg, is_status_file); + + } while (!feof(fp)); + + free(buf); + fclose(fp); + + return ret; +} + +/* + * Load in feed files from the cached "src" and/or "src/gz" locations. + */ +int +pkg_hash_load_feeds(void) +{ + pkg_src_list_elt_t *iter; + pkg_src_t *src, *subdist; + char *list_file, *lists_dir; + + opkg_msg(INFO, "\n"); + + lists_dir = conf->restrict_to_default_dest ? + conf->default_dest->lists_dir : conf->lists_dir; + + for (iter = void_list_first(&conf->dist_src_list); iter; + iter = void_list_next(&conf->dist_src_list, iter)) { + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name); + + if (file_exists(list_file)) { + int i; + release_t *release = release_new(); + if(release_init_from_file(release, list_file)) { + free(list_file); + return -1; + } + + unsigned int ncomp; + const char **comps = release_comps(release, &ncomp); + subdist = (pkg_src_t *) xmalloc(sizeof(pkg_src_t)); + memcpy(subdist, src, sizeof(pkg_src_t)); + + for(i = 0; i < ncomp; i++){ + subdist->name = NULL; + sprintf_alloc(&subdist->name, "%s-%s", src->name, comps[i]); + if (dist_hash_add_from_file(lists_dir, subdist)) { + free(subdist->name); free(subdist); + free(list_file); + return -1; + } + } + free(subdist->name); free(subdist); + } + free(list_file); + } + + for (iter = void_list_first(&conf->pkg_src_list); iter; + iter = void_list_next(&conf->pkg_src_list, iter)) { + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name); + + if (file_exists(list_file)) { + if (pkg_hash_add_from_file(list_file, src, NULL, 0)) { + free(list_file); + return -1; + } + } + free(list_file); + } + + return 0; +} + +/* + * Load in status files from the configured "dest"s. + */ +int +pkg_hash_load_status_files(void) +{ + pkg_dest_list_elt_t *iter; + pkg_dest_t *dest; + + opkg_msg(INFO, "\n"); + + for (iter = void_list_first(&conf->pkg_dest_list); iter; + iter = void_list_next(&conf->pkg_dest_list, iter)) { + + dest = (pkg_dest_t *)iter->data; + + if (file_exists(dest->status_file_name)) { + if (pkg_hash_add_from_file(dest->status_file_name, NULL, dest, 1)) + return -1; + } + } + + return 0; +} + +static abstract_pkg_t * +abstract_pkg_fetch_by_name(const char * pkg_name) +{ + return (abstract_pkg_t *)hash_table_get(&conf->pkg_hash, pkg_name); +} + +pkg_t * +pkg_hash_fetch_best_installation_candidate(abstract_pkg_t *apkg, + int (*constraint_fcn)(pkg_t *pkg, void *cdata), + void *cdata, int quiet) +{ + int i, j; + int nprovides = 0; + int nmatching = 0; + int wrong_arch_found = 0; + pkg_vec_t *matching_pkgs; + abstract_pkg_vec_t *matching_apkgs; + abstract_pkg_vec_t *provided_apkg_vec; + abstract_pkg_t **provided_apkgs; + abstract_pkg_vec_t *providers; + pkg_t *latest_installed_parent = NULL; + pkg_t *latest_matching = NULL; + pkg_t *priorized_matching = NULL; + pkg_t *held_pkg = NULL; + pkg_t *good_pkg_by_name = NULL; + + if (apkg == NULL || apkg->provided_by == NULL || (apkg->provided_by->len == 0)) + return NULL; + + matching_pkgs = pkg_vec_alloc(); + matching_apkgs = abstract_pkg_vec_alloc(); + providers = abstract_pkg_vec_alloc(); + + opkg_msg(DEBUG, "Best installation candidate for %s:\n", apkg->name); + + provided_apkg_vec = apkg->provided_by; + nprovides = provided_apkg_vec->len; + provided_apkgs = provided_apkg_vec->pkgs; + if (nprovides > 1) + opkg_msg(DEBUG, "apkg=%s nprovides=%d.\n", apkg->name, nprovides); + + /* accumulate all the providers */ + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *provider_apkg = provided_apkgs[i]; + opkg_msg(DEBUG, "Adding %s to providers.\n", provider_apkg->name); + abstract_pkg_vec_insert(providers, provider_apkg); + } + nprovides = providers->len; + + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *provider_apkg = abstract_pkg_vec_get(providers, i); + abstract_pkg_t *replacement_apkg = NULL; + pkg_vec_t *vec; + + if (provider_apkg->replaced_by && provider_apkg->replaced_by->len) { + replacement_apkg = provider_apkg->replaced_by->pkgs[0]; + if (provider_apkg->replaced_by->len > 1) { + opkg_msg(NOTICE, "Multiple replacers for %s, " + "using first one (%s).\n", + provider_apkg->name, replacement_apkg->name); + } + } + + if (replacement_apkg) + opkg_msg(DEBUG, "replacement_apkg=%s for provider_apkg=%s.\n", + replacement_apkg->name, provider_apkg->name); + + if (replacement_apkg && (replacement_apkg != provider_apkg)) { + if (abstract_pkg_vec_contains(providers, replacement_apkg)) + continue; + else + provider_apkg = replacement_apkg; + } + + if (!(vec = provider_apkg->pkgs)) { + opkg_msg(DEBUG, "No pkgs for provider_apkg %s.\n", + provider_apkg->name); + continue; + } + + + /* now check for supported architecture */ + { + int max_count = 0; + + /* count packages matching max arch priority and keep track of last one */ + for (j=0; j<vec->len; j++) { + pkg_t *maybe = vec->pkgs[j]; + opkg_msg(DEBUG, "%s arch=%s arch_priority=%d version=%s.\n", + maybe->name, maybe->architecture, + maybe->arch_priority, maybe->version); + /* We make sure not to add the same package twice. Need to search for the reason why + they show up twice sometimes. */ + if ((maybe->arch_priority > 0) && (! pkg_vec_contains(matching_pkgs, maybe))) { + max_count++; + abstract_pkg_vec_insert(matching_apkgs, maybe->parent); + pkg_vec_insert(matching_pkgs, maybe); + } + } + + if (vec->len > 0 && matching_pkgs->len < 1) + wrong_arch_found = 1; + } + } + + if (matching_pkgs->len < 1) { + if (wrong_arch_found) + opkg_msg(ERROR, "Packages for %s found, but" + " incompatible with the architectures configured\n", + apkg->name); + pkg_vec_free(matching_pkgs); + abstract_pkg_vec_free(matching_apkgs); + abstract_pkg_vec_free(providers); + return NULL; + } + + + if (matching_pkgs->len > 1) + pkg_vec_sort(matching_pkgs, pkg_name_version_and_architecture_compare); + if (matching_apkgs->len > 1) + abstract_pkg_vec_sort(matching_pkgs, abstract_pkg_name_compare); + + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + if (constraint_fcn(matching, cdata)) { + opkg_msg(DEBUG, "Candidate: %s %s.\n", + matching->name, matching->version) ; + good_pkg_by_name = matching; + /* It has been provided by hand, so it is what user want */ + if (matching->provided_by_hand == 1) + break; + } + } + + + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + latest_matching = matching; + if (matching->parent->state_status == SS_INSTALLED || matching->parent->state_status == SS_UNPACKED) + latest_installed_parent = matching; + if (matching->state_flag & (SF_HOLD|SF_PREFER)) { + if (held_pkg) + opkg_msg(NOTICE, "Multiple packages (%s and %s) providing" + " same name marked HOLD or PREFER. " + "Using latest.\n", + held_pkg->name, matching->name); + held_pkg = matching; + } + } + + if (!good_pkg_by_name && !held_pkg && !latest_installed_parent && matching_apkgs->len > 1 && !quiet) { + int prio = 0; + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + if (matching->arch_priority > prio) { + priorized_matching = matching; + prio = matching->arch_priority; + opkg_msg(DEBUG, "Match %s with priority %i.\n", + matching->name, prio); + } + } + + } + + if (conf->verbosity >= INFO && matching_apkgs->len > 1) { + opkg_msg(INFO, "%d matching pkgs for apkg=%s:\n", + matching_pkgs->len, apkg->name); + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + opkg_msg(INFO, "%s %s %s\n", + matching->name, matching->version, + matching->architecture); + } + } + + nmatching = matching_apkgs->len; + + pkg_vec_free(matching_pkgs); + abstract_pkg_vec_free(matching_apkgs); + abstract_pkg_vec_free(providers); + + if (good_pkg_by_name) { /* We found a good candidate, we will install it */ + return good_pkg_by_name; + } + if (held_pkg) { + opkg_msg(INFO, "Using held package %s.\n", held_pkg->name); + return held_pkg; + } + if (latest_installed_parent) { + opkg_msg(INFO, "Using latest version of installed package %s.\n", + latest_installed_parent->name); + return latest_installed_parent; + } + if (priorized_matching) { + opkg_msg(INFO, "Using priorized matching %s %s %s.\n", + priorized_matching->name, priorized_matching->version, + priorized_matching->architecture); + return priorized_matching; + } + if (nmatching > 1) { + opkg_msg(INFO, "No matching pkg out of %d matching_apkgs.\n", + nmatching); + return NULL; + } + if (latest_matching) { + opkg_msg(INFO, "Using latest matching %s %s %s.\n", + latest_matching->name, latest_matching->version, + latest_matching->architecture); + return latest_matching; + } + return NULL; +} + +static int +pkg_name_constraint_fcn(pkg_t *pkg, void *cdata) +{ + const char *name = (const char *)cdata; + + if (strcmp(pkg->name, name) == 0) + return 1; + else + return 0; +} + +static pkg_vec_t * +pkg_vec_fetch_by_name(const char *pkg_name) +{ + abstract_pkg_t * ab_pkg; + + if(!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name))) + return NULL; + + if (ab_pkg->pkgs) + return ab_pkg->pkgs; + + if (ab_pkg->provided_by) { + abstract_pkg_t *abpkg = abstract_pkg_vec_get(ab_pkg->provided_by, 0); + if (abpkg != NULL) + return abpkg->pkgs; + else + return ab_pkg->pkgs; + } + + return NULL; +} + + +pkg_t * +pkg_hash_fetch_best_installation_candidate_by_name(const char *name) +{ + abstract_pkg_t *apkg = NULL; + + if (!(apkg = abstract_pkg_fetch_by_name(name))) + return NULL; + + return pkg_hash_fetch_best_installation_candidate(apkg, + pkg_name_constraint_fcn, apkg->name, 0); +} + + +pkg_t * +pkg_hash_fetch_by_name_version(const char *pkg_name, const char * version) +{ + pkg_vec_t * vec; + int i; + char *version_str = NULL; + + if(!(vec = pkg_vec_fetch_by_name(pkg_name))) + return NULL; + + for(i = 0; i < vec->len; i++) { + version_str = pkg_version_str_alloc(vec->pkgs[i]); + if(!strcmp(version_str, version)) { + free(version_str); + break; + } + free(version_str); + } + + if(i == vec->len) + return NULL; + + return vec->pkgs[i]; +} + +pkg_t * +pkg_hash_fetch_installed_by_name_dest(const char *pkg_name, pkg_dest_t *dest) +{ + pkg_vec_t * vec; + int i; + + if (!(vec = pkg_vec_fetch_by_name(pkg_name))) { + return NULL; + } + + for (i = 0; i < vec->len; i++) + if((vec->pkgs[i]->state_status == SS_INSTALLED + || vec->pkgs[i]->state_status == SS_UNPACKED) + && vec->pkgs[i]->dest == dest) { + return vec->pkgs[i]; + } + + return NULL; +} + +pkg_t * +pkg_hash_fetch_installed_by_name(const char *pkg_name) +{ + pkg_vec_t * vec; + int i; + + if (!(vec = pkg_vec_fetch_by_name(pkg_name))) { + return NULL; + } + + for (i = 0; i < vec->len; i++) { + if (vec->pkgs[i]->state_status == SS_INSTALLED + || vec->pkgs[i]->state_status == SS_UNPACKED) { + return vec->pkgs[i]; + } + } + + return NULL; +} + + +static void +pkg_hash_fetch_available_helper(const char *pkg_name, void *entry, void *data) +{ + int j; + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *all = (pkg_vec_t *)data; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + pkg_vec_insert(all, pkg); + } +} + +void +pkg_hash_fetch_available(pkg_vec_t *all) +{ + hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_available_helper, + all); +} + +static void +pkg_hash_fetch_all_installed_helper(const char *pkg_name, void *entry, void *data) +{ + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *all = (pkg_vec_t *)data; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + int j; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (pkg->state_status == SS_INSTALLED + || pkg->state_status == SS_UNPACKED) + pkg_vec_insert(all, pkg); + } +} + +void +pkg_hash_fetch_all_installed(pkg_vec_t *all) +{ + hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_all_installed_helper, + all); +} + +/* + * This assumes that the abstract pkg doesn't exist. + */ +static abstract_pkg_t * +add_new_abstract_pkg_by_name(const char *pkg_name) +{ + abstract_pkg_t *ab_pkg; + + ab_pkg = abstract_pkg_new(); + + ab_pkg->name = xstrdup(pkg_name); + hash_table_insert(&conf->pkg_hash, pkg_name, ab_pkg); + + return ab_pkg; +} + + +abstract_pkg_t * +ensure_abstract_pkg_by_name(const char *pkg_name) +{ + abstract_pkg_t * ab_pkg; + + if (!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name))) + ab_pkg = add_new_abstract_pkg_by_name(pkg_name); + + return ab_pkg; +} + +void +hash_insert_pkg(pkg_t *pkg, int set_status) +{ + abstract_pkg_t * ab_pkg; + + ab_pkg = ensure_abstract_pkg_by_name(pkg->name); + if (!ab_pkg->pkgs) + ab_pkg->pkgs = pkg_vec_alloc(); + + if (pkg->state_status == SS_INSTALLED) { + ab_pkg->state_status = SS_INSTALLED; + } else if (pkg->state_status == SS_UNPACKED) { + ab_pkg->state_status = SS_UNPACKED; + } + + buildDepends(pkg); + + buildProvides(ab_pkg, pkg); + + /* Need to build the conflicts graph before replaces for correct + * calculation of replaced_by relation. + */ + buildConflicts(pkg); + + buildReplaces(ab_pkg, pkg); + + buildDependedUponBy(pkg, ab_pkg); + + pkg_vec_insert_merge(ab_pkg->pkgs, pkg, set_status); + pkg->parent = ab_pkg; +} + +static const char * +strip_offline_root(const char *file_name) +{ + unsigned int len; + + if (conf->offline_root) { + len = strlen(conf->offline_root); + if (strncmp(file_name, conf->offline_root, len) == 0) + file_name += len; + } + + return file_name; +} + +void +file_hash_remove(const char *file_name) +{ + file_name = strip_offline_root(file_name); + hash_table_remove(&conf->file_hash, file_name); +} + +pkg_t * +file_hash_get_file_owner(const char *file_name) +{ + file_name = strip_offline_root(file_name); + return hash_table_get(&conf->file_hash, file_name); +} + +void +file_hash_set_file_owner(const char *file_name, pkg_t *owning_pkg) +{ + pkg_t *old_owning_pkg; + + file_name = strip_offline_root(file_name); + + old_owning_pkg = hash_table_get(&conf->file_hash, file_name); + hash_table_insert(&conf->file_hash, file_name, owning_pkg); + + if (old_owning_pkg) { + pkg_get_installed_files(old_owning_pkg); + str_list_remove_elt(old_owning_pkg->installed_files, file_name); + pkg_free_installed_files(old_owning_pkg); + + /* mark this package to have its filelist written */ + old_owning_pkg->state_flag |= SF_FILELIST_CHANGED; + owning_pkg->state_flag |= SF_FILELIST_CHANGED; + } +} diff --git a/src/libopkg/.svn/text-base/pkg_hash.h.svn-base b/src/libopkg/.svn/text-base/pkg_hash.h.svn-base new file mode 100644 index 0000000..b3cf3d1 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_hash.h.svn-base @@ -0,0 +1,56 @@ +/* pkg_hash.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PKG_HASH_H +#define PKG_HASH_H + +#include "pkg.h" +#include "pkg_src.h" +#include "pkg_dest.h" +#include "hash_table.h" + + +void pkg_hash_init(void); +void pkg_hash_deinit(void); + +void pkg_hash_fetch_available(pkg_vec_t *available); + +int dist_hash_add_from_file(const char *file_name, pkg_src_t *dist); +int pkg_hash_add_from_file(const char *file_name, pkg_src_t *src, + pkg_dest_t *dest, int is_status_file); +int pkg_hash_load_feeds(void); +int pkg_hash_load_status_files(void); + +void hash_insert_pkg(pkg_t *pkg, int set_status); + +abstract_pkg_t * ensure_abstract_pkg_by_name(const char * pkg_name); +void pkg_hash_fetch_all_installed(pkg_vec_t *installed); +pkg_t * pkg_hash_fetch_by_name_version(const char *pkg_name, + const char * version); +pkg_t *pkg_hash_fetch_best_installation_candidate(abstract_pkg_t *apkg, + int (*constraint_fcn)(pkg_t *pkg, void *data), void *cdata, int quiet); +pkg_t *pkg_hash_fetch_best_installation_candidate_by_name(const char *name); +pkg_t *pkg_hash_fetch_installed_by_name(const char *pkg_name); +pkg_t *pkg_hash_fetch_installed_by_name_dest(const char *pkg_name, + pkg_dest_t *dest); + +void file_hash_remove(const char *file_name); +pkg_t *file_hash_get_file_owner(const char *file_name); +void file_hash_set_file_owner(const char *file_name, pkg_t *pkg); + +#endif + diff --git a/src/libopkg/.svn/text-base/pkg_parse.c.svn-base b/src/libopkg/.svn/text-base/pkg_parse.c.svn-base new file mode 100644 index 0000000..406220b --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_parse.c.svn-base @@ -0,0 +1,285 @@ +/* pkg_parse.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Steven M. Ayer + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <ctype.h> + +#include "opkg_utils.h" +#include "pkg_parse.h" +#include "libbb/libbb.h" + +#include "parse_util.h" + +static void +parse_status(pkg_t *pkg, const char *sstr) +{ + char sw_str[64], sf_str[64], ss_str[64]; + + if (sscanf(sstr, "Status: %63s %63s %63s", + sw_str, sf_str, ss_str) != 3) { + opkg_msg(ERROR, "Failed to parse Status line for %s\n", + pkg->name); + return; + } + + pkg->state_want = pkg_state_want_from_str(sw_str); + pkg->state_flag = pkg_state_flag_from_str(sf_str); + pkg->state_status = pkg_state_status_from_str(ss_str); +} + +static void +parse_conffiles(pkg_t *pkg, const char *cstr) +{ + char file_name[1024], md5sum[35]; + + if (sscanf(cstr, "%1023s %34s", file_name, md5sum) != 2) { + opkg_msg(ERROR, "Failed to parse Conffiles line for %s\n", + pkg->name); + return; + } + + conffile_list_append(&pkg->conffiles, file_name, md5sum); +} + +int +parse_version(pkg_t *pkg, const char *vstr) +{ + char *colon; + + if (strncmp(vstr, "Version:", 8) == 0) + vstr += 8; + + while (*vstr && isspace(*vstr)) + vstr++; + + colon = strchr(vstr, ':'); + if (colon) { + errno = 0; + pkg->epoch = strtoul(vstr, NULL, 10); + if (errno) { + opkg_perror(ERROR, "%s: invalid epoch", pkg->name); + } + vstr = ++colon; + } else { + pkg->epoch= 0; + } + + pkg->version = xstrdup(vstr); + pkg->revision = strrchr(pkg->version,'-'); + + if (pkg->revision) + *pkg->revision++ = '\0'; + + return 0; +} + +static int +get_arch_priority(const char *arch) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (strcmp(nv->name, arch) == 0) + return strtol(nv->value, NULL, 0); + } + return 0; +} + +int +pkg_parse_line(void *ptr, const char *line, uint mask) +{ + pkg_t *pkg = (pkg_t *) ptr; + + /* these flags are a bit hackish... */ + static int reading_conffiles = 0, reading_description = 0; + int ret = 0; + + /* Exclude globally masked fields. */ + mask |= conf->pfm; + + /* Flip the semantics of the mask. */ + mask ^= PFM_ALL; + + switch (*line) { + case 'A': + if ((mask & PFM_ARCHITECTURE ) && is_field("Architecture", line)) { + pkg->architecture = parse_simple("Architecture", line); + pkg->arch_priority = get_arch_priority(pkg->architecture); + } else if ((mask & PFM_AUTO_INSTALLED) && is_field("Auto-Installed", line)) { + char *tmp = parse_simple("Auto-Installed", line); + if (strcmp(tmp, "yes") == 0) + pkg->auto_installed = 1; + free(tmp); + } + break; + + case 'C': + if ((mask & PFM_CONFFILES) && is_field("Conffiles", line)) { + reading_conffiles = 1; + reading_description = 0; + goto dont_reset_flags; + } + else if ((mask & PFM_CONFLICTS) && is_field("Conflicts", line)) + pkg->conflicts_str = parse_list(line, &pkg->conflicts_count, ',', 0); + break; + + case 'D': + if ((mask & PFM_DESCRIPTION) && is_field("Description", line)) { + pkg->description = parse_simple("Description", line); + reading_conffiles = 0; + reading_description = 1; + goto dont_reset_flags; + } else if ((mask & PFM_DEPENDS) && is_field("Depends", line)) + pkg->depends_str = parse_list(line, &pkg->depends_count, ',', 0); + break; + + case 'E': + if((mask & PFM_ESSENTIAL) && is_field("Essential", line)) { + char *tmp = parse_simple("Essential", line); + if (strcmp(tmp, "yes") == 0) + pkg->essential = 1; + free(tmp); + } + break; + + case 'F': + if((mask & PFM_FILENAME) && is_field("Filename", line)) + pkg->filename = parse_simple("Filename", line); + break; + + case 'I': + if ((mask & PFM_INSTALLED_SIZE) && is_field("Installed-Size", line)) { + char *tmp = parse_simple("Installed-Size", line); + pkg->installed_size = strtoul(tmp, NULL, 0); + free (tmp); + } else if ((mask & PFM_INSTALLED_TIME) && is_field("Installed-Time", line)) { + char *tmp = parse_simple("Installed-Time", line); + pkg->installed_time = strtoul(tmp, NULL, 0); + free (tmp); + } + break; + + case 'M': + if ((mask & PFM_MD5SUM) && is_field("MD5sum:", line)) + pkg->md5sum = parse_simple("MD5sum", line); + /* The old opkg wrote out status files with the wrong + * case for MD5sum, let's parse it either way */ + else if ((mask & PFM_MD5SUM) && is_field("MD5Sum:", line)) + pkg->md5sum = parse_simple("MD5Sum", line); + else if((mask & PFM_MAINTAINER) && is_field("Maintainer", line)) + pkg->maintainer = parse_simple("Maintainer", line); + break; + + case 'P': + if ((mask & PFM_PACKAGE) && is_field("Package", line)) + pkg->name = parse_simple("Package", line); + else if ((mask & PFM_PRIORITY) && is_field("Priority", line)) + pkg->priority = parse_simple("Priority", line); + else if ((mask & PFM_PROVIDES) && is_field("Provides", line)) + pkg->provides_str = parse_list(line, &pkg->provides_count, ',', 0); + else if ((mask & PFM_PRE_DEPENDS) && is_field("Pre-Depends", line)) + pkg->pre_depends_str = parse_list(line, &pkg->pre_depends_count, ',', 0); + break; + + case 'R': + if ((mask & PFM_RECOMMENDS) && is_field("Recommends", line)) + pkg->recommends_str = parse_list(line, &pkg->recommends_count, ',', 0); + else if ((mask & PFM_REPLACES) && is_field("Replaces", line)) + pkg->replaces_str = parse_list(line, &pkg->replaces_count, ',', 0); + + break; + + case 'S': + if ((mask & PFM_SECTION) && is_field("Section", line)) + pkg->section = parse_simple("Section", line); +#ifdef HAVE_SHA256 + else if ((mask & PFM_SHA256SUM) && is_field("SHA256sum", line)) + pkg->sha256sum = parse_simple("SHA256sum", line); +#endif + else if ((mask & PFM_SIZE) && is_field("Size", line)) { + char *tmp = parse_simple("Size", line); + pkg->size = strtoul(tmp, NULL, 0); + free (tmp); + } else if ((mask & PFM_SOURCE) && is_field("Source", line)) + pkg->source = parse_simple("Source", line); + else if ((mask & PFM_STATUS) && is_field("Status", line)) + parse_status(pkg, line); + else if ((mask & PFM_SUGGESTS) && is_field("Suggests", line)) + pkg->suggests_str = parse_list(line, &pkg->suggests_count, ',', 0); + break; + + case 'T': + if ((mask & PFM_TAGS) && is_field("Tags", line)) + pkg->tags = parse_simple("Tags", line); + break; + + case 'V': + if ((mask & PFM_VERSION) && is_field("Version", line)) + parse_version(pkg, line); + break; + + case ' ': + if ((mask & PFM_DESCRIPTION) && reading_description) { + pkg->description = xrealloc(pkg->description, + strlen(pkg->description) + + 1 + strlen(line) + 1); + strcat(pkg->description, "\n"); + strcat(pkg->description, (line)); + goto dont_reset_flags; + } else if ((mask & PFM_CONFFILES) && reading_conffiles) { + parse_conffiles(pkg, line); + goto dont_reset_flags; + } + + /* FALLTHROUGH */ + default: + /* For package lists, signifies end of package. */ + if(line_is_blank(line)) { + ret = 1; + break; + } + } + + reading_description = 0; + reading_conffiles = 0; + +dont_reset_flags: + + return ret; +} + +int +pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask) +{ + int ret; + char *buf; + const size_t len = 4096; + + buf = xmalloc(len); + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, mask, &buf, len); + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + free(buf); + + return ret; +} diff --git a/src/libopkg/.svn/text-base/pkg_parse.h.svn-base b/src/libopkg/.svn/text-base/pkg_parse.h.svn-base new file mode 100644 index 0000000..4e2b8e0 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_parse.h.svn-base @@ -0,0 +1,57 @@ +/* pkg_parse.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PKG_PARSE_H +#define PKG_PARSE_H + +#include "pkg.h" + +int parse_version(pkg_t *pkg, const char *raw); +int pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask); +int pkg_parse_line(void *ptr, const char *line, uint mask); + +/* package field mask */ +#define PFM_ARCHITECTURE (1 << 1) +#define PFM_AUTO_INSTALLED (1 << 2) +#define PFM_CONFFILES (1 << 3) +#define PFM_CONFLICTS (1 << 4) +#define PFM_DESCRIPTION (1 << 5) +#define PFM_DEPENDS (1 << 6) +#define PFM_ESSENTIAL (1 << 7) +#define PFM_FILENAME (1 << 8) +#define PFM_INSTALLED_SIZE (1 << 9) +#define PFM_INSTALLED_TIME (1 << 10) +#define PFM_MD5SUM (1 << 11) +#define PFM_MAINTAINER (1 << 12) +#define PFM_PACKAGE (1 << 13) +#define PFM_PRIORITY (1 << 14) +#define PFM_PROVIDES (1 << 15) +#define PFM_PRE_DEPENDS (1 << 16) +#define PFM_RECOMMENDS (1 << 17) +#define PFM_REPLACES (1 << 18) +#define PFM_SECTION (1 << 19) +#define PFM_SHA256SUM (1 << 20) +#define PFM_SIZE (1 << 21) +#define PFM_SOURCE (1 << 22) +#define PFM_STATUS (1 << 23) +#define PFM_SUGGESTS (1 << 24) +#define PFM_TAGS (1 << 25) +#define PFM_VERSION (1 << 26) + +#define PFM_ALL (~(uint)0) + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_src.c.svn-base b/src/libopkg/.svn/text-base/pkg_src.c.svn-base new file mode 100644 index 0000000..690fef6 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_src.c.svn-base @@ -0,0 +1,39 @@ +/* pkg_src.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "pkg_src.h" +#include "libbb/libbb.h" + +int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip) +{ + src->gzip = gzip; + src->name = xstrdup(name); + src->value = xstrdup(base_url); + if (extra_data) + src->extra_data = xstrdup(extra_data); + else + src->extra_data = NULL; + return 0; +} + +void pkg_src_deinit(pkg_src_t *src) +{ + free (src->name); + free (src->value); + if (src->extra_data) + free (src->extra_data); +} diff --git a/src/libopkg/.svn/text-base/pkg_src.h.svn-base b/src/libopkg/.svn/text-base/pkg_src.h.svn-base new file mode 100644 index 0000000..b1a95a5 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_src.h.svn-base @@ -0,0 +1,34 @@ +/* pkg_src.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_SRC_H +#define PKG_SRC_H + +#include "nv_pair.h" + +typedef struct +{ + char *name; + char *value; + char *extra_data; + int gzip; +} pkg_src_t; + +int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip); +void pkg_src_deinit(pkg_src_t *src); + +#endif diff --git a/src/libopkg/.svn/text-base/pkg_src_list.c.svn-base b/src/libopkg/.svn/text-base/pkg_src_list.c.svn-base new file mode 100644 index 0000000..7ad1b41 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_src_list.c.svn-base @@ -0,0 +1,64 @@ +/* pkg_src_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "pkg_src_list.h" +#include "void_list.h" +#include "libbb/libbb.h" + +void pkg_src_list_init(pkg_src_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void pkg_src_list_deinit(pkg_src_list_t *list) +{ + pkg_src_list_elt_t *iter, *n; + pkg_src_t *pkg_src; + + list_for_each_entry_safe(iter, n, &list->head, node) { + pkg_src = (pkg_src_t *)iter->data; + pkg_src_deinit(pkg_src); + + /* malloced in pkg_src_list_append */ + free(pkg_src); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +pkg_src_t *pkg_src_list_append(pkg_src_list_t *list, + const char *name, const char *base_url, const char *extra_data, + int gzip) +{ + /* freed in pkg_src_list_deinit */ + pkg_src_t *pkg_src = xcalloc(1, sizeof(pkg_src_t)); + pkg_src_init(pkg_src, name, base_url, extra_data, gzip); + + void_list_append((void_list_t *) list, pkg_src); + + return pkg_src; +} + +void pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list) +{ + return (pkg_src_list_elt_t *) void_list_pop((void_list_t *) list); +} diff --git a/src/libopkg/.svn/text-base/pkg_src_list.h.svn-base b/src/libopkg/.svn/text-base/pkg_src_list.h.svn-base new file mode 100644 index 0000000..529f013 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_src_list.h.svn-base @@ -0,0 +1,44 @@ +/* pkg_src_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_SRC_LIST_H +#define PKG_SRC_LIST_H + +#include "pkg_src.h" +#include "void_list.h" + +typedef struct void_list_elt pkg_src_list_elt_t; + +typedef struct void_list pkg_src_list_t; + +static inline int pkg_src_list_empty(pkg_src_list_t *list) +{ + return void_list_empty((void_list_t *)list); +} + +void pkg_src_list_elt_init(pkg_src_list_elt_t *elt, nv_pair_t *data); +void pkg_src_list_elt_deinit(pkg_src_list_elt_t *elt); + +void pkg_src_list_init(pkg_src_list_t *list); +void pkg_src_list_deinit(pkg_src_list_t *list); + +pkg_src_t *pkg_src_list_append(pkg_src_list_t *list, const char *name, const char *root_dir, const char *extra_data, int gzip); +void pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data); +pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list); + +#endif + diff --git a/src/libopkg/.svn/text-base/pkg_vec.c.svn-base b/src/libopkg/.svn/text-base/pkg_vec.c.svn-base new file mode 100644 index 0000000..472962c --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_vec.c.svn-base @@ -0,0 +1,208 @@ +/* pkg_vec.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <stdio.h> +#include <fnmatch.h> + +#include "pkg.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + +pkg_vec_t * pkg_vec_alloc(void) +{ + pkg_vec_t * vec = xcalloc(1, sizeof(pkg_vec_t)); + vec->pkgs = NULL; + vec->len = 0; + + return vec; +} + +void pkg_vec_free(pkg_vec_t *vec) +{ + if (!vec) + return; + + if (vec->pkgs) + free(vec->pkgs); + + free(vec); +} + +/* + * assumption: all names in a vector are identical + * assumption: all version strings are trimmed, + * so identical versions have identical version strings, + * implying identical packages; let's marry these + */ +void pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status) +{ + int i; + int found = 0; + + /* look for a duplicate pkg by name, version, and architecture */ + for (i = 0; i < vec->len; i++){ + opkg_msg(DEBUG2, "%s %s arch=%s vs. %s %s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture, + vec->pkgs[i]->name, vec->pkgs[i]->version, + vec->pkgs[i]->architecture); + /* if the name,ver,arch matches, or the name matches and the + * package is marked deinstall/hold */ + if ((!strcmp(pkg->name, vec->pkgs[i]->name)) + && ((pkg->state_want == SW_DEINSTALL + && (pkg->state_flag & SF_HOLD)) + || ((pkg_compare_versions(pkg, vec->pkgs[i]) == 0) + && (!strcmp(pkg->architecture, vec->pkgs[i]->architecture))))) { + found = 1; + opkg_msg(DEBUG2, "Duplicate for pkg=%s version=%s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture); + break; + } + } + + /* we didn't find one, add it */ + if (!found){ + opkg_msg(DEBUG2, "Adding new pkg=%s version=%s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture); + pkg_vec_insert(vec, pkg); + return; + } + + /* update the one that we have */ + opkg_msg(DEBUG2, "Merging %s %s arch=%s, set_status=%d.\n", + pkg->name, pkg->version, pkg->architecture, set_status); + if (set_status) { + /* This is from the status file, + * so need to merge with existing database */ + pkg_merge(pkg, vec->pkgs[i]); + } + + /* overwrite the old one */ + pkg_deinit(vec->pkgs[i]); + free(vec->pkgs[i]); + vec->pkgs[i] = pkg; +} + +void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg) +{ + vec->pkgs = xrealloc(vec->pkgs, (vec->len + 1) * sizeof(pkg_t *)); + vec->pkgs[vec->len] = (pkg_t *)pkg; + vec->len++; +} + +int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg) +{ + int i; + for (i = 0; i < vec->len; i++) + if (vec->pkgs[i] == apkg) + return 1; + return 0; +} + +void pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar) +{ + qsort(vec->pkgs, vec->len, sizeof(pkg_t *), compar); +} + +int pkg_vec_clear_marks(pkg_vec_t *vec) +{ + int npkgs = vec->len; + int i; + for (i = 0; i < npkgs; i++) { + pkg_t *pkg = vec->pkgs[i]; + pkg->state_flag &= ~SF_MARKED; + } + return 0; +} + +int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern) +{ + int matching_count = 0; + pkg_t **pkgs = vec->pkgs; + int npkgs = vec->len; + int i; + for (i = 0; i < npkgs; i++) { + pkg_t *pkg = pkgs[i]; + if (fnmatch(pattern, pkg->name, 0)==0) { + pkg->state_flag |= SF_MARKED; + matching_count++; + } + } + return matching_count; +} + + +abstract_pkg_vec_t * abstract_pkg_vec_alloc(void) +{ + abstract_pkg_vec_t * vec ; + vec = xcalloc(1, sizeof(abstract_pkg_vec_t)); + vec->pkgs = NULL; + vec->len = 0; + + return vec; +} + +void abstract_pkg_vec_free(abstract_pkg_vec_t *vec) +{ + if (!vec) + return; + free(vec->pkgs); + free(vec); +} + +/* + * assumption: all names in a vector are unique + */ +void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg) +{ + vec->pkgs = xrealloc(vec->pkgs, (vec->len + 1) * sizeof(abstract_pkg_t *)); + vec->pkgs[vec->len] = pkg; + vec->len++; +} + +abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i) +{ + if (vec->len > i) + return vec->pkgs[i]; + else + return NULL; +} + +int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg) +{ + int i; + for (i = 0; i < vec->len; i++) + if (vec->pkgs[i] == apkg) + return 1; + return 0; +} + +void abstract_pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar) +{ + qsort(vec->pkgs, vec->len, sizeof(pkg_t *), compar); +} + +int pkg_compare_names(const void *p1, const void *p2) +{ + const pkg_t *pkg1 = *(const pkg_t **)p1; + const pkg_t *pkg2 = *(const pkg_t **)p2; + if (pkg1->name == NULL) + return 1; + if (pkg2->name == NULL) + return -1; + return(strcmp(pkg1->name, pkg2->name)); +} + diff --git a/src/libopkg/.svn/text-base/pkg_vec.h.svn-base b/src/libopkg/.svn/text-base/pkg_vec.h.svn-base new file mode 100644 index 0000000..8ee1673 --- /dev/null +++ b/src/libopkg/.svn/text-base/pkg_vec.h.svn-base @@ -0,0 +1,63 @@ +/* pkg_vec.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PKG_VEC_H +#define PKG_VEC_H + +typedef struct pkg pkg_t; +typedef struct abstract_pkg abstract_pkg_t; +typedef struct pkg_vec pkg_vec_t; +typedef struct abstract_pkg_vec abstract_pkg_vec_t; + +#include "opkg_conf.h" + +struct pkg_vec +{ + pkg_t **pkgs; + unsigned int len; +}; + +struct abstract_pkg_vec +{ + abstract_pkg_t **pkgs; + unsigned int len; +}; + + +pkg_vec_t * pkg_vec_alloc(void); +void pkg_vec_free(pkg_vec_t *vec); + +void pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status); +void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg); +int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg); + +typedef int (*compare_fcn_t)(const void *, const void *); +void pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar); + +int pkg_vec_clear_marks(pkg_vec_t *vec); +int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern); + +abstract_pkg_vec_t * abstract_pkg_vec_alloc(void); +void abstract_pkg_vec_free(abstract_pkg_vec_t *vec); +void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg); +abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i); +int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg); +void abstract_pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar); + +int pkg_compare_names(const void *p1, const void *p2); +#endif + diff --git a/src/libopkg/.svn/text-base/release.c.svn-base b/src/libopkg/.svn/text-base/release.c.svn-base new file mode 100644 index 0000000..1b6e838 --- /dev/null +++ b/src/libopkg/.svn/text-base/release.c.svn-base @@ -0,0 +1,342 @@ +/* release.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#include <unistd.h> +#include <ctype.h> + +#include "release.h" +#include "opkg_utils.h" +#include "libbb/libbb.h" + +#include "opkg_download.h" +#include "sprintf_alloc.h" + +#include "release_parse.h" + +#include "parse_util.h" +#include "file_util.h" + +static void +release_init(release_t *release) +{ + release->name = NULL; + release->datestring = NULL; + release->architectures = NULL; + release->architectures_count = 0; + release->components = NULL; + release->components_count = 0; + release->complist = NULL; + release->complist_count = 0; +} + +release_t * +release_new(void) +{ + release_t *release; + + release = xcalloc(1, sizeof(release_t)); + release_init(release); + + return release; +} + +void +release_deinit(release_t *release) +{ + int i; + + free(release->name); + free(release->datestring); + + for(i = 0; i < release->architectures_count; i++){ + free(release->architectures[i]); + } + free(release->architectures); + + for(i = 0; i < release->components_count; i++){ + free(release->components[i]); + } + free(release->components); + + for(i = 0; i < release->complist_count; i++){ + free(release->complist[i]); + } + free(release->complist); + +} + +int +release_init_from_file(release_t *release, const char *filename) +{ + int err = 0; + FILE *release_file; + + release_file = fopen(filename, "r"); + if (release_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", filename); + return -1; + } + + err=release_parse_from_stream(release, release_file); + if (!err) { + if (!release_arch_supported(release)) { + opkg_msg(ERROR, "No valid architecture found on Release file.\n"); + err = -1; + } + } + + return err; +} + +const char * +item_in_list(const char *comp, char **complist, const unsigned int count) +{ + int i; + + if (!complist) + return comp; + + for(i = 0; i < count; i++){ + if (strcmp(comp, complist[i]) == 0) + return complist[i]; + } + + return NULL; +} + +int +release_arch_supported(release_t *release) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (item_in_list(nv->name, release->architectures, release->architectures_count)) { + opkg_msg(DEBUG, "Arch %s (priority %s) supported for dist %s.\n", + nv->name, nv->value, release->name); + return 1; + } + } + + return 0; +} + +int +release_comps_supported(release_t *release, const char *complist) +{ + int ret = 1; + int i; + + if (complist) { + release->complist = parse_list(complist, &release->complist_count, ' ', 1); + for(i = 0; i < release->complist_count; i++){ + if (!item_in_list(release->complist[i], release->components, release->components_count)) { + opkg_msg(ERROR, "Component %s not supported for dist %s.\n", + release->complist[i], release->name); + ret = 0; + } + } + } + + return ret; +} + +const char ** +release_comps(release_t *release, unsigned int *count) +{ + char **comps = release->complist; + + if (!comps) { + comps = release->components; + *count = release->components_count; + } else { + *count = release->complist_count; + } + + return (const char **)comps; +} + +int +release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir) +{ + int ret = 0; + unsigned int ncomp; + const char **comps = release_comps(release, &ncomp); + nv_pair_list_elt_t *l; + int i; + + for(i = 0; i < ncomp; i++){ + int err = 0; + char *prefix; + + sprintf_alloc(&prefix, "%s/dists/%s/%s/binary", dist->value, dist->name, + comps[i]); + + list_for_each_entry(l , &conf->arch_list.head, node) { + char *url; + char *tmp_file_name, *list_file_name; + char *subpath = NULL; + + nv_pair_t *nv = (nv_pair_t *)l->data; + + sprintf_alloc(&list_file_name, "%s/%s-%s-%s", lists_dir, dist->name, comps[i], nv->name); + + sprintf_alloc(&tmp_file_name, "%s/%s-%s-%s%s", tmpdir, dist->name, comps[i], nv->name, ".gz"); + + sprintf_alloc(&subpath, "%s/binary-%s/%s", comps[i], nv->name, dist->gzip ? "Packages.gz" : "Packages"); + + if (dist->gzip) { + sprintf_alloc(&url, "%s-%s/Packages.gz", prefix, nv->name); + err = opkg_download(url, tmp_file_name, NULL, NULL, 1); + if (!err) { + err = release_verify_file(release, tmp_file_name, subpath); + if (err) { + unlink (tmp_file_name); + unlink (list_file_name); + } + } + if (!err) { + FILE *in, *out; + opkg_msg(NOTICE, "Inflating %s.\n", url); + in = fopen (tmp_file_name, "r"); + out = fopen (list_file_name, "w"); + if (in && out) { + err = unzip (in, out); + if (err) + opkg_msg(INFO, "Corrumpt file at %s.\n", url); + } else + err = 1; + if (in) + fclose (in); + if (out) + fclose (out); + unlink (tmp_file_name); + } + free(url); + } + + if (err) { + sprintf_alloc(&url, "%s-%s/Packages", prefix, nv->name); + err = opkg_download(url, list_file_name, NULL, NULL, 1); + if (!err) { + err = release_verify_file(release, tmp_file_name, subpath); + if (err) + unlink (list_file_name); + } + free(url); + } + + free(tmp_file_name); + free(list_file_name); + } + + if(err) + ret = 1; + + free(prefix); + } + + return ret; +} + +int +release_get_size(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->md5sums) { + cksum = cksum_list_find(release->md5sums, pathname); + return cksum->size; + } + +#ifdef HAVE_SHA256 + if (release->sha256sums) { + cksum = cksum_list_find(release->sha256sums, pathname); + return cksum->size; + } +#endif + + return -1; +} + +const char * +release_get_md5(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->md5sums) { + cksum = cksum_list_find(release->md5sums, pathname); + return cksum->value; + } + + return '\0'; +} + +#ifdef HAVE_SHA256 +const char * +release_get_sha256(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->sha256sums) { + cksum = cksum_list_find(release->sha256sums, pathname); + return cksum->value; + } + + return '\0'; +} +#endif + +int +release_verify_file(release_t *release, const char* file_name, const char *pathname) +{ + struct stat f_info; + char *f_md5 = NULL; + const char *md5 = release_get_md5(release, pathname); +#ifdef HAVE_SHA256 + char *f_sha256 = NULL; + const char *sha256 = release_get_sha256(release, pathname); +#endif + int ret = 0; + + if (stat(file_name, &f_info) || (f_info.st_size!=release_get_size(release, pathname))) { + opkg_msg(ERROR, "Size verification failed for %s - %s.\n", release->name, pathname); + ret = 1; + } else { + + f_md5 = file_md5sum_alloc(file_name); +#ifdef HAVE_SHA256 + f_sha256 = file_sha256sum_alloc(file_name); +#endif + + if (md5 && strcmp(md5, f_md5)) { + opkg_msg(ERROR, "MD5 verification failed for %s - %s.\n", release->name, pathname); + ret = 1; +#ifdef HAVE_SHA256 + } else if (sha256 && strcmp(sha256, f_sha256)) { + opkg_msg(ERROR, "SHA256 verification failed for %s - %s.\n", release->name, pathname); + ret = 1; +#endif + } + + } + + free(f_md5); +#ifdef HAVE_SHA256 + free(f_sha256); +#endif + + return ret; +} diff --git a/src/libopkg/.svn/text-base/release.h.svn-base b/src/libopkg/.svn/text-base/release.h.svn-base new file mode 100644 index 0000000..239dcca --- /dev/null +++ b/src/libopkg/.svn/text-base/release.h.svn-base @@ -0,0 +1,53 @@ +/* release.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#ifndef RELEASE_H +#define RELEASE_H + +#include <stdio.h> +#include "pkg.h" +#include "cksum_list.h" + +struct release +{ + char *name; + char *datestring; + char **architectures; + unsigned int architectures_count; + char **components; + unsigned int components_count; + cksum_list_t *md5sums; +#ifdef HAVE_SHA256 + cksum_list_t *sha256sums; +#endif + char **complist; + unsigned int complist_count; +}; + +typedef struct release release_t; + +release_t *release_new(void); +void release_deinit(release_t *release); +int release_init_from_file(release_t *release, const char *filename); + +int release_arch_supported(release_t *release); +int release_comps_supported(release_t *release, const char *complist); +int release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir); + +const char **release_comps(release_t *release, unsigned int *count); + +int release_verify_file(release_t *release, const char *filename, const char *pathname); + +#endif diff --git a/src/libopkg/.svn/text-base/release_parse.c.svn-base b/src/libopkg/.svn/text-base/release_parse.c.svn-base new file mode 100644 index 0000000..f411045 --- /dev/null +++ b/src/libopkg/.svn/text-base/release_parse.c.svn-base @@ -0,0 +1,126 @@ +/* release_parse.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> + +#include "release.h" +#include "release_parse.h" +#include "libbb/libbb.h" +#include "parse_util.h" + +static int +release_parse_line(void *ptr, const char *line, uint mask) +{ + release_t *release = (release_t *) ptr; + + int ret = 0; + unsigned int count = 0; + char **list = 0; + static int reading_md5sums = 0; +#ifdef HAVE_SHA256 + static int reading_sha256sums = 0; +#endif + + switch (*line) { + case 'A': + if (is_field("Architectures", line)) { + release->architectures = parse_list(line, &release->architectures_count, ' ', 0); + } + break; + + case 'C': + if (is_field("Codename", line)) { + release->name = parse_simple("Codename", line); + } + else if (is_field("Components", line)) { + release->components = parse_list(line, &release->components_count, ' ', 0); + } + break; + + case 'D': + if (is_field("Date", line)) { + release->datestring = parse_simple("Date", line); + } + break; + + case 'M': + if (is_field("MD5sum", line)) { + reading_md5sums = 1; + if (release->md5sums == NULL) { + release->md5sums = xcalloc(1, sizeof(cksum_list_t)); + cksum_list_init(release->md5sums); + } + goto dont_reset_flags; + } + break; + +#ifdef HAVE_SHA256 + case 'S': + if (is_field("SHA256", line)) { + reading_sha256sums = 1; + if (release->sha256sums == NULL) { + release->sha256sums = xcalloc(1, sizeof(cksum_list_t)); + cksum_list_init(release->sha256sums); + } + goto dont_reset_flags; + } + break; +#endif + + case ' ': + if (reading_md5sums) { + list = parse_list(line, &count, ' ', 1); + cksum_list_append(release->md5sums, list); + goto dont_reset_flags; + } +#ifdef HAVE_SHA256 + else if (reading_sha256sums) { + list = parse_list(line, &count, ' ', 1); + cksum_list_append(release->sha256sums, list); + goto dont_reset_flags; + } +#endif + break; + + default: + ret = 1; + } + + reading_md5sums = 0; +#ifdef HAVE_SHA256 + reading_sha256sums = 0; +#endif + +dont_reset_flags: + + return ret; +} + +int +release_parse_from_stream(release_t *release, FILE *fp) +{ + int ret; + char *buf; + const size_t len = 4096; + + buf = xmalloc(len); + ret = parse_from_stream_nomalloc(release_parse_line, release, fp, 0, &buf, len); + free(buf); + + return ret; +} + diff --git a/src/libopkg/.svn/text-base/release_parse.h.svn-base b/src/libopkg/.svn/text-base/release_parse.h.svn-base new file mode 100644 index 0000000..5840df6 --- /dev/null +++ b/src/libopkg/.svn/text-base/release_parse.h.svn-base @@ -0,0 +1,21 @@ +/* release_parse.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#ifndef RELEASE_PARSE_H +#define RELEASE_PARSE_H + +int release_parse_from_stream(release_t *release, FILE *fp); + +#endif diff --git a/src/libopkg/.svn/text-base/sha256.c.svn-base b/src/libopkg/.svn/text-base/sha256.c.svn-base new file mode 100644 index 0000000..0ad9444 --- /dev/null +++ b/src/libopkg/.svn/text-base/sha256.c.svn-base @@ -0,0 +1,554 @@ +/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or + memory blocks according to the NIST specification FIPS-180-2. + + Copyright (C) 2005, 2006, 2008 Free Software Foundation, 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 3 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by David Madore, considerably copypasting from + Scott G. Miller's sha1.c +*/ + +#include <config.h> + +#include "sha256.h" + +#include <stddef.h> +#include <string.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 256 bit block of data (eight 32 bit ints) and + intializes it to the start constants of the SHA256 algorithm. This + must be called before using hash in the call to sha256_hash +*/ +void +sha256_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0x6a09e667UL; + ctx->state[1] = 0xbb67ae85UL; + ctx->state[2] = 0x3c6ef372UL; + ctx->state[3] = 0xa54ff53aUL; + ctx->state[4] = 0x510e527fUL; + ctx->state[5] = 0x9b05688cUL; + ctx->state[6] = 0x1f83d9abUL; + ctx->state[7] = 0x5be0cd19UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +void +sha224_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0xc1059ed8UL; + ctx->state[1] = 0x367cd507UL; + ctx->state[2] = 0x3070dd17UL; + ctx->state[3] = 0xf70e5939UL; + ctx->state[4] = 0xffc00b31UL; + ctx->state[5] = 0x68581511UL; + ctx->state[6] = 0x64f98fa7UL; + ctx->state[7] = 0xbefa4fa4UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Copy the value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void +set_uint32 (char *cp, uint32_t v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 32 bytes following RESBUF. The result + must be in little endian byte order. */ +void * +sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 8; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +void * +sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 7; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +static void +sha256_conclude_ctx (struct sha256_ctx *ctx) +{ + /* Take yet unprocessed bytes into account. */ + size_t bytes = ctx->buflen; + size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. + Use set_uint32 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint32 ((char *) &ctx->buffer[size - 2], + SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29))); + set_uint32 ((char *) &ctx->buffer[size - 1], + SWAP (ctx->total[0] << 3)); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + sha256_process_block (ctx->buffer, size * 4, ctx); +} + +void * +sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha256_read_ctx (ctx, resbuf); +} + +void * +sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha224_read_ctx (ctx, resbuf); +} + +/* Compute SHA256 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 bytes + beginning at RESBLOCK. */ +int +sha256_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha256_finish_ctx (&ctx, resblock); + return 0; +} + +/* FIXME: Avoid code duplication */ +int +sha224_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha224_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +sha256_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha256_finish_ctx (&ctx, resblock); +} + +void * +sha224_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha224_finish_ctx (&ctx, resblock); +} + +void +sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + sha256_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + sha256_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha256.c --- */ + +/* SHA256 round constants */ +#define K(I) sha256_round_constants[I] +static const uint32_t sha256_round_constants[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, +}; + +/* Round functions. */ +#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) +#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void +sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + const uint32_t *words = buffer; + size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t x[16]; + uint32_t a = ctx->state[0]; + uint32_t b = ctx->state[1]; + uint32_t c = ctx->state[2]; + uint32_t d = ctx->state[3]; + uint32_t e = ctx->state[4]; + uint32_t f = ctx->state[5]; + uint32_t g = ctx->state[6]; + uint32_t h = ctx->state[7]; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + +#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) +#define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) +#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) +#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) + +#define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \ + + S0(x[(I-15)&0x0f]) + x[I&0x0f] \ + , x[I&0x0f] = tm ) + +#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ + t1 = H + SS1(E) \ + + F1(E,F,G) \ + + K \ + + M; \ + D += t1; H = t0 + t1; \ + } while(0) + + while (words < endp) + { + uint32_t tm; + uint32_t t0, t1; + int t; + /* FIXME: see sha1.c for a better implementation. */ + for (t = 0; t < 16; t++) + { + x[t] = SWAP (*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + + a = ctx->state[0] += a; + b = ctx->state[1] += b; + c = ctx->state[2] += c; + d = ctx->state[3] += d; + e = ctx->state[4] += e; + f = ctx->state[5] += f; + g = ctx->state[6] += g; + h = ctx->state[7] += h; + } +} diff --git a/src/libopkg/.svn/text-base/sha256.h.svn-base b/src/libopkg/.svn/text-base/sha256.h.svn-base new file mode 100644 index 0000000..6a9aed4 --- /dev/null +++ b/src/libopkg/.svn/text-base/sha256.h.svn-base @@ -0,0 +1,91 @@ +/* Declarations of functions and data types used for SHA256 and SHA224 sum + library functions. + Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, 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 3 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef SHA256_H +# define SHA256_H 1 + +# include <stdio.h> +# include <stdint.h> + +# ifdef __cplusplus +extern "C" { +# endif + +/* Structure to save state of computation between the single steps. */ +struct sha256_ctx +{ + uint32_t state[8]; + + uint32_t total[2]; + size_t buflen; + uint32_t buffer[32]; +}; + +enum { SHA224_DIGEST_SIZE = 224 / 8 }; +enum { SHA256_DIGEST_SIZE = 256 / 8 }; + +/* Initialize structure containing state of computation. */ +extern void sha256_init_ctx (struct sha256_ctx *ctx); +extern void sha224_init_ctx (struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void sha256_process_block (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void sha256_process_bytes (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 32 (28) bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 32 (28) bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +extern void *sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf); + + +/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 (28) bytes + beginning at RESBLOCK. */ +extern int sha256_stream (FILE *stream, void *resblock); +extern int sha224_stream (FILE *stream, void *resblock); + +/* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha256_buffer (const char *buffer, size_t len, void *resblock); +extern void *sha224_buffer (const char *buffer, size_t len, void *resblock); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/libopkg/.svn/text-base/sprintf_alloc.c.svn-base b/src/libopkg/.svn/text-base/sprintf_alloc.c.svn-base new file mode 100644 index 0000000..aef8e06 --- /dev/null +++ b/src/libopkg/.svn/text-base/sprintf_alloc.c.svn-base @@ -0,0 +1,49 @@ +/* sprintf_alloc.c -- like sprintf with memory allocation + + Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.com> + + 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, 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. +*/ + +#include <stdarg.h> + +#include "sprintf_alloc.h" +#include "libbb/libbb.h" + +void +sprintf_alloc(char **str, const char *fmt, ...) +{ + va_list ap; + int n; + unsigned int size = 0; + + *str = NULL; + + for (;;) { + va_start(ap, fmt); + n = vsnprintf (*str, size, fmt, ap); + va_end(ap); + + if (n < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vsnprintf.\n", + __FUNCTION__); + exit(EXIT_FAILURE); + } + + if (n < size) + break; + + /* Truncated, try again with more space. */ + size = n+1; + *str = xrealloc(*str, size); + } +} diff --git a/src/libopkg/.svn/text-base/sprintf_alloc.h.svn-base b/src/libopkg/.svn/text-base/sprintf_alloc.h.svn-base new file mode 100644 index 0000000..bcf42a4 --- /dev/null +++ b/src/libopkg/.svn/text-base/sprintf_alloc.h.svn-base @@ -0,0 +1,23 @@ +/* sprintf_alloca.c -- like sprintf with memory allocation + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef SPRINTF_ALLOC_H +#define SPRINTF_ALLOC_H + +void sprintf_alloc(char **str, const char *fmt, ...); + +#endif diff --git a/src/libopkg/.svn/text-base/str_list.c.svn-base b/src/libopkg/.svn/text-base/str_list.c.svn-base new file mode 100644 index 0000000..d3a0179 --- /dev/null +++ b/src/libopkg/.svn/text-base/str_list.c.svn-base @@ -0,0 +1,112 @@ +/* str_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "str_list.h" +#include "libbb/libbb.h" + +void str_list_elt_init(str_list_elt_t *elt, char *data) +{ + void_list_elt_init((void_list_elt_t *) elt, data); +} + +void str_list_elt_deinit(str_list_elt_t *elt) +{ + if (elt->data) + free(elt->data); + void_list_elt_deinit((void_list_elt_t *) elt); +} + +str_list_t *str_list_alloc() +{ + str_list_t *list = xcalloc(1, sizeof(str_list_t)); + str_list_init(list); + return list; +} + +void str_list_init(str_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void str_list_deinit(str_list_t *list) +{ + str_list_elt_t *elt; + while (!void_list_empty(list)) { + elt = str_list_first(list); + if (!elt) + return; + list_del_init(&elt->node); + free(elt->data); + elt->data=NULL; + free(elt); + } +} + +void str_list_append(str_list_t *list, char *data) +{ + void_list_append((void_list_t *) list, xstrdup(data)); +} + +void str_list_push(str_list_t *list, char *data) +{ + void_list_push((void_list_t *) list, xstrdup(data)); +} + +str_list_elt_t *str_list_pop(str_list_t *list) +{ + return (str_list_elt_t *) void_list_pop((void_list_t *) list); +} + +void str_list_remove(str_list_t *list, str_list_elt_t **iter) +{ + char *str = void_list_remove((void_list_t *) list, + (void_list_elt_t **) iter); + + if (str) + free(str); +} + +void str_list_remove_elt(str_list_t *list, const char *target_str) +{ + char *str = void_list_remove_elt((void_list_t *) list, + (void *)target_str, + (void_list_cmp_t)strcmp); + if (str) + free(str); +} + +str_list_elt_t *str_list_first(str_list_t *list) { + return (str_list_elt_t * )void_list_first((void_list_t *) list); +} + +str_list_elt_t *str_list_prev(str_list_t *list, str_list_elt_t *node) { + return (str_list_elt_t * )void_list_prev((void_list_t *) list, (void_list_elt_t *)node); +} + +str_list_elt_t *str_list_next(str_list_t *list, str_list_elt_t *node) { + return (str_list_elt_t * )void_list_next((void_list_t *) list, (void_list_elt_t *)node); +} + +str_list_elt_t *str_list_last(str_list_t *list) { + return (str_list_elt_t * )void_list_last((void_list_t *) list); +} + + +void str_list_purge(str_list_t *list) { + str_list_deinit(list); + free(list); +} diff --git a/src/libopkg/.svn/text-base/str_list.h.svn-base b/src/libopkg/.svn/text-base/str_list.h.svn-base new file mode 100644 index 0000000..3690820 --- /dev/null +++ b/src/libopkg/.svn/text-base/str_list.h.svn-base @@ -0,0 +1,47 @@ +/* str_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef STR_LIST_H +#define STR_LIST_H + +#include "void_list.h" + +typedef struct void_list_elt str_list_elt_t; + +typedef struct void_list str_list_t; + +void str_list_elt_init(str_list_elt_t *elt, char *data); +void str_list_elt_deinit(str_list_elt_t *elt); + +str_list_t *str_list_alloc(void); +void str_list_init(str_list_t *list); +void str_list_deinit(str_list_t *list); + +void str_list_append(str_list_t *list, char *data); +void str_list_push(str_list_t *list, char *data); +str_list_elt_t *str_list_pop(str_list_t *list); +void str_list_remove(str_list_t *list, str_list_elt_t **iter); +void str_list_remove_elt(str_list_t *list, const char *target_str); + +str_list_elt_t *str_list_first(str_list_t *list); +str_list_elt_t *str_list_prev(str_list_t *list, str_list_elt_t *node); +str_list_elt_t *str_list_next(str_list_t *list, str_list_elt_t *node); +str_list_elt_t *str_list_last(str_list_t *list); + +void str_list_purge(str_list_t *list); + +#endif diff --git a/src/libopkg/.svn/text-base/void_list.c.svn-base b/src/libopkg/.svn/text-base/void_list.c.svn-base new file mode 100644 index 0000000..4c9d897 --- /dev/null +++ b/src/libopkg/.svn/text-base/void_list.c.svn-base @@ -0,0 +1,165 @@ +/* void_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "void_list.h" +#include "libbb/libbb.h" + +void void_list_elt_init(void_list_elt_t *elt, void *data) +{ + INIT_LIST_HEAD(&elt->node); + elt->data = data; +} + +static void_list_elt_t * void_list_elt_new (void *data) { + void_list_elt_t *elt; + /* freed in void_list_elt_deinit */ + elt = xcalloc(1, sizeof(void_list_elt_t)); + void_list_elt_init(elt, data); + return elt; +} + +void void_list_elt_deinit(void_list_elt_t *elt) +{ + list_del_init(&elt->node); + void_list_elt_init(elt, NULL); + free(elt); +} + +void void_list_init(void_list_t *list) +{ + INIT_LIST_HEAD(&list->head); +} + +void void_list_deinit(void_list_t *list) +{ + void_list_elt_t *elt; + + while (!void_list_empty(list)) { + elt = void_list_pop(list); + void_list_elt_deinit(elt); + } + INIT_LIST_HEAD(&list->head); +} + +void void_list_append(void_list_t *list, void *data) +{ + void_list_elt_t *elt = void_list_elt_new(data); + list_add_tail(&elt->node, &list->head); +} + +void void_list_push(void_list_t *list, void *data) +{ + void_list_elt_t *elt = void_list_elt_new(data); + list_add(&elt->node, &list->head); +} + +void_list_elt_t *void_list_pop(void_list_t *list) +{ + struct list_head *node; + + if (void_list_empty(list)) + return NULL; + node = list->head.next; + list_del_init(node); + return list_entry(node, void_list_elt_t, node); +} + +void *void_list_remove(void_list_t *list, void_list_elt_t **iter) +{ + void_list_elt_t *pos, *n; + void_list_elt_t *old_elt; + void *old_data = NULL; + + old_elt = *iter; + if (!old_elt) + return old_data; + old_data = old_elt->data; + + list_for_each_entry_safe(pos, n, &list->head, node) { + if (pos == old_elt) + break; + } + if ( pos != old_elt) { + opkg_msg(ERROR, "Internal error: element not found in list.\n"); + return NULL; + } + + *iter = list_entry(pos->node.prev, void_list_elt_t, node); + void_list_elt_deinit(pos); + + return old_data; +} + +/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */ +void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp) +{ + void_list_elt_t *pos, *n; + void *old_data = NULL; + list_for_each_entry_safe(pos, n, &list->head, node) { + if ( pos->data && cmp(pos->data, target_data)==0 ){ + old_data = pos->data; + void_list_elt_deinit(pos); + break; + } + } + return old_data; +} + +void_list_elt_t *void_list_first(void_list_t *list) { + struct list_head *elt; + if (!list) + return NULL; + elt = list->head.next; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_prev(void_list_t *list, void_list_elt_t *node) { + struct list_head *elt; + if (!list || !node) + return NULL; + elt = node->node.prev; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_next(void_list_t *list, void_list_elt_t *node) { + struct list_head *elt; + if (!list || !node) + return NULL; + elt = node->node.next; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_last(void_list_t *list) { + struct list_head *elt; + if (!list) + return NULL; + elt = list->head.prev; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + diff --git a/src/libopkg/.svn/text-base/void_list.h.svn-base b/src/libopkg/.svn/text-base/void_list.h.svn-base new file mode 100644 index 0000000..b63a68d --- /dev/null +++ b/src/libopkg/.svn/text-base/void_list.h.svn-base @@ -0,0 +1,64 @@ +/* void_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef VOID_LIST_H +#define VOID_LIST_H + +#include "list.h" + +typedef struct void_list_elt void_list_elt_t; +struct void_list_elt +{ + struct list_head node; + void *data; +}; + +typedef struct void_list void_list_t; +struct void_list +{ + struct list_head head; +}; + +static inline int void_list_empty(void_list_t *list) +{ + return list_empty(&list->head); +} + +void void_list_elt_init(void_list_elt_t *elt, void *data); +void void_list_elt_deinit(void_list_elt_t *elt); + +void void_list_init(void_list_t *list); +void void_list_deinit(void_list_t *list); + +void void_list_append(void_list_t *list, void *data); +void void_list_push(void_list_t *list, void *data); +void_list_elt_t *void_list_pop(void_list_t *list); + +void *void_list_remove(void_list_t *list, void_list_elt_t **iter); +/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */ +typedef int (*void_list_cmp_t)(const void *, const void *); +void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp); + +void_list_elt_t *void_list_first(void_list_t *list); +void_list_elt_t *void_list_prev(void_list_t *list, void_list_elt_t *node); +void_list_elt_t *void_list_next(void_list_t *list, void_list_elt_t *node); +void_list_elt_t *void_list_last(void_list_t *list); + +void void_list_purge(void_list_t *list); + + +#endif diff --git a/src/libopkg/.svn/text-base/xregex.c.svn-base b/src/libopkg/.svn/text-base/xregex.c.svn-base new file mode 100644 index 0000000..f682d4c --- /dev/null +++ b/src/libopkg/.svn/text-base/xregex.c.svn-base @@ -0,0 +1,46 @@ +/* xregex.c - regex functions with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "xregex.h" +#include "libbb/libbb.h" + +static void print_regcomp_err(const regex_t *preg, int err); + +int xregcomp(regex_t *preg, const char *regex, int cflags) +{ + int err; + err = regcomp(preg, regex, cflags); + if (err) { + print_regcomp_err(preg, err); + } + + return err; +} + +static void print_regcomp_err(const regex_t *preg, int err) +{ + unsigned int size; + char *error; + + size = regerror(err, preg, 0, 0); + error = xcalloc(1, size); + regerror(err, preg, error, size); + + opkg_msg(ERROR, "Internal error compiling regex: %s.", error); + + free(error); +} diff --git a/src/libopkg/.svn/text-base/xregex.h.svn-base b/src/libopkg/.svn/text-base/xregex.h.svn-base new file mode 100644 index 0000000..f67572b --- /dev/null +++ b/src/libopkg/.svn/text-base/xregex.h.svn-base @@ -0,0 +1,31 @@ +/* xregex.h - regex functions with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef XREGEX_H +#define XREGEX_H + +#include <sys/types.h> +#include <regex.h> + +int xregcomp(regex_t *preg, const char *regex, int cflags); +static inline void xregfree(regex_t *preg) +{ + regfree(preg); +} + + +#endif diff --git a/src/libopkg/.svn/text-base/xsystem.c.svn-base b/src/libopkg/.svn/text-base/xsystem.c.svn-base new file mode 100644 index 0000000..ae7ca87 --- /dev/null +++ b/src/libopkg/.svn/text-base/xsystem.c.svn-base @@ -0,0 +1,73 @@ +/* xsystem.c - system(3) with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "xsystem.h" +#include "libbb/libbb.h" + +/* Like system(3), but with error messages printed if the fork fails + or if the child process dies due to an uncaught signal. Also, the + return value is a bit simpler: + + -1 if there was any problem + Otherwise, the 8-bit return value of the program ala WEXITSTATUS + as defined in <sys/wait.h>. +*/ +int +xsystem(const char *argv[]) +{ + int status; + pid_t pid; + + pid = vfork(); + + switch (pid) { + case -1: + opkg_perror(ERROR, "%s: vfork", argv[0]); + return -1; + case 0: + /* child */ + execvp(argv[0], (char*const*)argv); + _exit(-1); + default: + /* parent */ + break; + } + + if (waitpid(pid, &status, 0) == -1) { + opkg_perror(ERROR, "%s: waitpid", argv[0]); + return -1; + } + + if (WIFSIGNALED(status)) { + opkg_msg(ERROR, "%s: Child killed by signal %d.\n", + argv[0], WTERMSIG(status)); + return -1; + } + + if (!WIFEXITED(status)) { + /* shouldn't happen */ + opkg_msg(ERROR, "%s: Your system is broken: got status %d " + "from waitpid.\n", argv[0], status); + return -1; + } + + return WEXITSTATUS(status); +} diff --git a/src/libopkg/.svn/text-base/xsystem.h.svn-base b/src/libopkg/.svn/text-base/xsystem.h.svn-base new file mode 100644 index 0000000..042efad --- /dev/null +++ b/src/libopkg/.svn/text-base/xsystem.h.svn-base @@ -0,0 +1,32 @@ +/* xsystem.h - system(3) with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef XSYSTEM_H +#define XSYSTEM_H + +/* Like system(3), but with error messages printed if the fork fails + or if the child process dies due to an uncaught signal. Also, the + return value is a bit simpler: + + -1 if there was any problem + Otherwise, the 8-bit return value of the program ala WEXITSTATUS + as defined in <sys/wait.h>. +*/ +int xsystem(const char *argv[]); + +#endif + diff --git a/src/libopkg/Makefile.am b/src/libopkg/Makefile.am new file mode 100644 index 0000000..043c5c4 --- /dev/null +++ b/src/libopkg/Makefile.am @@ -0,0 +1,55 @@ + +AM_CFLAGS=-Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DOPKGLOCKFILE=\"@opkglockfile@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) $(PATHFINDER_CFLAGS) + +libopkg_includedir=$(includedir)/libopkg +libopkg_include_HEADERS= *.h + + +opkg_libcore_sources = \ + opkg.c opkg.h \ + opkg_defines.h +opkg_cmd_sources = opkg_cmd.c opkg_cmd.h \ + opkg_configure.c opkg_configure.h \ + opkg_download.c opkg_download.h \ + opkg_install.c opkg_install.h \ + opkg_upgrade.c opkg_upgrade.h \ + opkg_remove.c opkg_remove.h +opkg_db_sources = opkg_conf.c opkg_conf.h \ + release.c release.h release_parse.c release_parse.h \ + opkg_utils.c opkg_utils.h pkg.c pkg.h hash_table.h \ + pkg_depends.c pkg_depends.h pkg_extract.c pkg_extract.h \ + hash_table.c pkg_hash.c pkg_hash.h pkg_parse.c pkg_parse.h \ + pkg_vec.c pkg_vec.h +opkg_list_sources = conffile.c conffile.h conffile_list.c conffile_list.h \ + nv_pair.c nv_pair.h nv_pair_list.c nv_pair_list.h \ + pkg_dest.c pkg_dest.h pkg_dest_list.c pkg_dest_list.h \ + pkg_src.c pkg_src.h pkg_src_list.c pkg_src_list.h \ + str_list.c str_list.h void_list.c void_list.h \ + active_list.c active_list.h list.h +opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c md5.c md5.h \ + parse_util.c parse_util.h \ + cksum_list.c cksum_list.h \ + sprintf_alloc.c sprintf_alloc.h \ + xregex.c xregex.h xsystem.c xsystem.h +if HAVE_PATHFINDER +opkg_util_sources += opkg_pathfinder.c opkg_pathfinder.h +endif +if HAVE_SHA256 +opkg_util_sources += sha256.c sha256.h +endif + +lib_LTLIBRARIES = libopkg.la +libopkg_la_SOURCES = \ + $(opkg_libcore_sources) \ + $(opkg_cmd_sources) $(opkg_db_sources) \ + $(opkg_util_sources) $(opkg_list_sources) + +libopkg_la_LIBADD = $(top_builddir)/libbb/libbb.la $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS) + +libopkg_la_LDFLAGS = -version-info 1:0:0 + +# make sure we only export symbols that are for public use +#libopkg_la_LDFLAGS = -export-symbols-regex "^opkg_.*" + + + diff --git a/src/libopkg/active_list.c b/src/libopkg/active_list.c new file mode 100644 index 0000000..69ac1d1 --- /dev/null +++ b/src/libopkg/active_list.c @@ -0,0 +1,165 @@ +/* active_list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko 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, 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. +*/ + + +#include "active_list.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "libbb/libbb.h" + +void active_list_init(struct active_list *ptr) { + INIT_LIST_HEAD(&ptr->node); + INIT_LIST_HEAD(&ptr->depend); + ptr->depended = NULL; +} + +/** + */ +struct active_list * active_list_next(struct active_list *head, struct active_list *ptr) { + struct active_list *next=NULL; + if ( !head ) { + opkg_msg(ERROR, "Internal error: head=%p, ptr=%p\n", head, ptr); + return NULL; + } + if ( !ptr ) + ptr = head; + next = list_entry(ptr->node.next, struct active_list, node); + if ( next == head ) { + return NULL; + } + if ( ptr->depended && &ptr->depended->depend == ptr->node.next ) { + return ptr->depended; + } + while ( next->depend.next != &next->depend ) { + next = list_entry(next->depend.next, struct active_list, node); + } + return next; +} + + +struct active_list * active_list_prev(struct active_list *head, struct active_list *ptr) { + struct active_list *prev=NULL; + if ( !head ) { + opkg_msg(ERROR, "Internal error: head=%p, ptr=%p\n", head, ptr); + return NULL; + } + if ( !ptr ) + ptr = head; + if ( ptr->depend.prev != &ptr->depend ) { + prev = list_entry(ptr->depend.prev, struct active_list, node); + return prev; + } + if ( ptr->depended && ptr->depended != head && &ptr->depended->depend == ptr->node.prev ) { + prev = list_entry(ptr->depended->node.prev, struct active_list, node); + } else + prev = list_entry(ptr->node.prev, struct active_list, node); + if ( prev == head ) + return NULL; + return prev; +} + + +struct active_list *active_list_move_node(struct active_list *old_head, struct active_list *new_head, struct active_list *node) { + struct active_list *prev; + if (!old_head || !new_head || !node) + return NULL; + if (old_head == new_head) + return node; + prev = active_list_prev(old_head, node); + active_list_add(new_head, node); + return prev; +} + +static void list_head_clear (struct list_head *head) { + struct active_list *next; + struct list_head *n, *ptr; + if (!head) + return; + list_for_each_safe(ptr, n , head) { + next = list_entry(ptr, struct active_list, node); + if (next->depend.next != &next->depend) { + list_head_clear(&next->depend); + } + active_list_init(next); + } +} +void active_list_clear(struct active_list *head) { + list_head_clear(&head->node); + if (head->depend.next != &head->depend) { + list_head_clear(&head->depend); + } + active_list_init(head); +} + +void active_list_add_depend(struct active_list *node, struct active_list *depend) { + list_del_init(&depend->node); + list_add_tail(&depend->node, &node->depend); + depend->depended = node; +} + +void active_list_add(struct active_list *head, struct active_list *node) { + list_del_init(&node->node); + list_add_tail(&node->node, &head->node); + node->depended = head; +} + +struct active_list * active_list_head_new(void) { + struct active_list * head = xcalloc(1, sizeof(struct active_list)); + active_list_init(head); + return head; +} + +void active_list_head_delete(struct active_list *head) { + active_list_clear(head); + free(head); +} + +/* + * Using insert sort. + * Note. the list should not be large, or it will be very inefficient. + * + */ +struct active_list * active_list_sort(struct active_list *head, int (*compare)(const void *, const void *)) { + struct active_list tmphead; + struct active_list *node, *ptr; + if ( !head ) + return NULL; + active_list_init(&tmphead); + for (node = active_list_next(head, NULL); node; node = active_list_next(head, NULL)) { + if (tmphead.node.next == &tmphead.node) { + active_list_move_node(head, &tmphead, node); + } else { + for (ptr = active_list_next(&tmphead, NULL); ptr; ptr=active_list_next(&tmphead, ptr)) { + if (compare(ptr, node) <= 0) { + break; + } + } + if (!ptr) { + active_list_move_node(head, &tmphead, node); + } else { + active_list_move_node(head, ptr, node); + } + } + node->depended = &tmphead; + } + for (ptr = active_list_prev(&tmphead, NULL); ptr; ptr=active_list_prev(&tmphead, NULL)) { + active_list_move_node(&tmphead, head, ptr); + } + return head; +} diff --git a/src/libopkg/active_list.h b/src/libopkg/active_list.h new file mode 100644 index 0000000..ecb79a6 --- /dev/null +++ b/src/libopkg/active_list.h @@ -0,0 +1,44 @@ +/* active_list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko 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, 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. +*/ + +#ifndef ACTIVE_LIST_H +#define ACTIVE_LIST_H + +#include "list.h" + +struct active_list { + struct list_head node; + struct list_head depend; + struct active_list *depended; +}; + + +struct active_list * active_list_head_new(void); +void active_list_head_delete(struct active_list *); +void active_list_init(struct active_list *ptr); +void active_list_clear(struct active_list *head); +void active_list_add_depend(struct active_list *node, struct active_list *depend); +void active_list_add(struct active_list *head, struct active_list *node); +struct active_list *active_list_move_node(struct active_list *old_head, struct active_list *new_head, struct active_list *node); + +struct active_list * active_list_sort(struct active_list *head, int (*compare_fcn_t)(const void *, const void *)); + +struct active_list * active_list_next(struct active_list *head, struct active_list *ptr); + +struct active_list * active_list_prev(struct active_list *head, struct active_list *ptr); + +#endif diff --git a/src/libopkg/cksum_list.c b/src/libopkg/cksum_list.c new file mode 100644 index 0000000..d17151d --- /dev/null +++ b/src/libopkg/cksum_list.c @@ -0,0 +1,87 @@ +/* cksum_lis.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> + +#include "cksum_list.h" +#include "libbb/libbb.h" + + +int cksum_init(cksum_t *cksum, char **itemlist) +{ + cksum->value = xstrdup(*itemlist++); + cksum->size = atoi(*itemlist++); + cksum->name = xstrdup(*itemlist++); + + return 0; +} + +void cksum_deinit(cksum_t *cksum) +{ + free (cksum->name); + cksum->name = NULL; + + free (cksum->value); + cksum->value = NULL; +} + +void cksum_list_init(cksum_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void cksum_list_deinit(cksum_list_t *list) +{ + cksum_list_elt_t *iter, *n; + cksum_t *cksum; + + list_for_each_entry_safe(iter, n, &list->head, node) { + cksum = (cksum_t *)iter->data; + cksum_deinit(cksum); + + /* malloced in cksum_list_append */ + free(cksum); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist) +{ + /* freed in cksum_list_deinit */ + cksum_t *cksum = xcalloc(1, sizeof(cksum_t)); + cksum_init(cksum, itemlist); + + void_list_append((void_list_t *) list, cksum); + + return cksum; +} + +const cksum_t *cksum_list_find(cksum_list_t *list, const char *name) +{ + cksum_list_elt_t *iter; + cksum_t *cksum; + + list_for_each_entry(iter, &list->head, node) { + cksum = (cksum_t *)iter->data; + if (strcmp(cksum->name, name) == 0) { + return cksum; + } + } + return NULL; +} + diff --git a/src/libopkg/cksum_list.h b/src/libopkg/cksum_list.h new file mode 100644 index 0000000..b752288 --- /dev/null +++ b/src/libopkg/cksum_list.h @@ -0,0 +1,46 @@ +/* cksum_list.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#ifndef CKSUM_LIST_H +#define CKSUM_LIST_H + +typedef struct +{ + char *name; + char *value; + int size; +} cksum_t; + +int cksum_init(cksum_t *cksum, char **itemlist); +void cksum_deinit(cksum_t *cksum); + +#include "void_list.h" + +typedef struct void_list_elt cksum_list_elt_t; + +typedef struct void_list cksum_list_t; + +static inline int cksum_list_empty(cksum_list_t *list) +{ + return void_list_empty ((void_list_t *)list); +} + +void cksum_list_init(cksum_list_t *list); +void cksum_list_deinit(cksum_list_t *list); + +cksum_t *cksum_list_append(cksum_list_t *list, char **itemlist); +const cksum_t *cksum_list_find(cksum_list_t *list, const char *name); + +#endif diff --git a/src/libopkg/conffile.c b/src/libopkg/conffile.c new file mode 100644 index 0000000..bf8b2a5 --- /dev/null +++ b/src/libopkg/conffile.c @@ -0,0 +1,63 @@ +/* conffile.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "opkg_message.h" +#include "conffile.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "opkg_conf.h" + +int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum) +{ + return nv_pair_init(conffile, file_name, md5sum); +} + +void conffile_deinit(conffile_t *conffile) +{ + nv_pair_deinit(conffile); +} + +int conffile_has_been_modified(conffile_t *conffile) +{ + char *md5sum; + char *filename = conffile->name; + char *root_filename; + int ret = 1; + + if (conffile->value == NULL) { + opkg_msg(NOTICE, "Conffile %s has no md5sum.\n", conffile->name); + return 1; + } + + root_filename = root_filename_alloc(filename); + + md5sum = file_md5sum_alloc(root_filename); + + if (md5sum && (ret = strcmp(md5sum, conffile->value))) { + opkg_msg(INFO, "Conffile %s:\n\told md5=%s\n\tnew md5=%s\n", + conffile->name, md5sum, conffile->value); + } + + free(root_filename); + if (md5sum) + free(md5sum); + + return ret; +} diff --git a/src/libopkg/conffile.h b/src/libopkg/conffile.h new file mode 100644 index 0000000..a188c6d --- /dev/null +++ b/src/libopkg/conffile.h @@ -0,0 +1,29 @@ +/* conffile.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef CONFFILE_H +#define CONFFILE_H + +#include "nv_pair.h" +typedef struct nv_pair conffile_t; + +int conffile_init(conffile_t *conffile, const char *file_name, const char *md5sum); +void conffile_deinit(conffile_t *conffile); +int conffile_has_been_modified(conffile_t *conffile); + +#endif + diff --git a/src/libopkg/conffile_list.c b/src/libopkg/conffile_list.c new file mode 100644 index 0000000..1db7790 --- /dev/null +++ b/src/libopkg/conffile_list.c @@ -0,0 +1,46 @@ +/* conffile_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "conffile_list.h" + +void conffile_list_init(conffile_list_t *list) +{ + nv_pair_list_init(list); +} + +void conffile_list_deinit(conffile_list_t *list) +{ + nv_pair_list_deinit(list); +} + +conffile_t *conffile_list_append(conffile_list_t *list, const char *file_name, + const char *md5sum) +{ + return nv_pair_list_append(list, file_name, md5sum); +} + +void conffile_list_push(conffile_list_t *list, conffile_t *data) +{ + nv_pair_list_push(list, data); +} + +conffile_list_elt_t *conffile_list_pop(conffile_list_t *list) +{ + conffile_list_elt_t *pos = nv_pair_list_pop(list); + return pos; +} + diff --git a/src/libopkg/conffile_list.h b/src/libopkg/conffile_list.h new file mode 100644 index 0000000..942f68e --- /dev/null +++ b/src/libopkg/conffile_list.h @@ -0,0 +1,37 @@ +/* conffile_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef CONFFILE_LIST_H +#define CONFFILE_LIST_H + +#include "nv_pair_list.h" + +typedef nv_pair_list_elt_t conffile_list_elt_t; +typedef nv_pair_list_t conffile_list_t; + +#include "conffile.h" + +void conffile_list_init(conffile_list_t *list); +void conffile_list_deinit(conffile_list_t *list); + +conffile_t *conffile_list_append(conffile_list_t *list, const char *name, + const char *root_dir); +void conffile_list_push(conffile_list_t *list, conffile_t *data); +conffile_list_elt_t *conffile_list_pop(conffile_list_t *list); + +#endif + diff --git a/src/libopkg/file_util.c b/src/libopkg/file_util.c new file mode 100644 index 0000000..897546e --- /dev/null +++ b/src/libopkg/file_util.c @@ -0,0 +1,315 @@ +/* file_util.c - convenience routines for common stat operations + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> + +#include "sprintf_alloc.h" +#include "file_util.h" +#include "md5.h" +#include "libbb/libbb.h" + +#if defined HAVE_SHA256 +#include "sha256.h" +#endif + +int +file_exists(const char *file_name) +{ + struct stat st; + + if (stat(file_name, &st) == -1) + return 0; + + return 1; +} + +int +file_is_dir(const char *file_name) +{ + struct stat st; + + if (stat(file_name, &st) == -1) + return 0; + + return S_ISDIR(st.st_mode); +} + +/* read a single line from a file, stopping at a newline or EOF. + If a newline is read, it will appear in the resulting string. + Return value is a malloc'ed char * which should be freed at + some point by the caller. + + Return value is NULL if the file is at EOF when called. +*/ +char * +file_read_line_alloc(FILE *fp) +{ + char buf[BUFSIZ]; + unsigned int buf_len; + char *line = NULL; + unsigned int line_size = 0; + int got_nl = 0; + + buf[0] = '\0'; + + while (fgets(buf, BUFSIZ, fp)) { + buf_len = strlen(buf); + if (buf[buf_len - 1] == '\n') { + buf_len--; + buf[buf_len] = '\0'; + got_nl = 1; + } + if (line) { + line_size += buf_len; + line = xrealloc(line, line_size+1); + strncat(line, buf, line_size); + } else { + line_size = buf_len + 1; + line = xstrdup(buf); + } + if (got_nl) + break; + } + + return line; +} + +int +file_move(const char *src, const char *dest) +{ + int err; + + err = rename(src, dest); + if (err == -1) { + if (errno == EXDEV) { + /* src & dest live on different file systems */ + err = file_copy(src, dest); + if (err == 0) + unlink(src); + } else { + opkg_perror(ERROR, "Failed to rename %s to %s", + src, dest); + } + } + + return err; +} + +int +file_copy(const char *src, const char *dest) +{ + int err; + + err = copy_file(src, dest, FILEUTILS_FORCE | FILEUTILS_PRESERVE_STATUS); + if (err) + opkg_msg(ERROR, "Failed to copy file %s to %s.\n", + src, dest); + + return err; +} + +int +file_mkdir_hier(const char *path, long mode) +{ + return make_directory(path, mode, FILEUTILS_RECUR); +} + +char *file_md5sum_alloc(const char *file_name) +{ + static const int md5sum_bin_len = 16; + static const int md5sum_hex_len = 32; + + static const unsigned char bin2hex[16] = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + + int i, err; + FILE *file; + char *md5sum_hex; + unsigned char md5sum_bin[md5sum_bin_len]; + + md5sum_hex = xcalloc(1, md5sum_hex_len + 1); + + file = fopen(file_name, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open file %s", file_name); + free(md5sum_hex); + return NULL; + } + + err = md5_stream(file, md5sum_bin); + if (err) { + opkg_msg(ERROR, "Could't compute md5sum for %s.\n", file_name); + fclose(file); + free(md5sum_hex); + return NULL; + } + + fclose(file); + + for (i=0; i < md5sum_bin_len; i++) { + md5sum_hex[i*2] = bin2hex[md5sum_bin[i] >> 4]; + md5sum_hex[i*2+1] = bin2hex[md5sum_bin[i] & 0xf]; + } + + md5sum_hex[md5sum_hex_len] = '\0'; + + return md5sum_hex; +} + +#ifdef HAVE_SHA256 +char *file_sha256sum_alloc(const char *file_name) +{ + static const int sha256sum_bin_len = 32; + static const int sha256sum_hex_len = 64; + + static const unsigned char bin2hex[16] = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + + int i, err; + FILE *file; + char *sha256sum_hex; + unsigned char sha256sum_bin[sha256sum_bin_len]; + + sha256sum_hex = xcalloc(1, sha256sum_hex_len + 1); + + file = fopen(file_name, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open file %s", file_name); + free(sha256sum_hex); + return NULL; + } + + err = sha256_stream(file, sha256sum_bin); + if (err) { + opkg_msg(ERROR, "Could't compute sha256sum for %s.\n", file_name); + fclose(file); + free(sha256sum_hex); + return NULL; + } + + fclose(file); + + for (i=0; i < sha256sum_bin_len; i++) { + sha256sum_hex[i*2] = bin2hex[sha256sum_bin[i] >> 4]; + sha256sum_hex[i*2+1] = bin2hex[sha256sum_bin[i] & 0xf]; + } + + sha256sum_hex[sha256sum_hex_len] = '\0'; + + return sha256sum_hex; +} + +#endif + + +int +rm_r(const char *path) +{ + int ret = 0; + DIR *dir; + struct dirent *dent; + + if (path == NULL) { + opkg_perror(ERROR, "Missing directory parameter"); + return -1; + } + + dir = opendir(path); + if (dir == NULL) { + opkg_perror(ERROR, "Failed to open dir %s", path); + return -1; + } + + if (fchdir(dirfd(dir)) == -1) { + opkg_perror(ERROR, "Failed to change to dir %s", path); + closedir(dir); + return -1; + } + + while (1) { + errno = 0; + if ((dent = readdir(dir)) == NULL) { + if (errno) { + opkg_perror(ERROR, "Failed to read dir %s", + path); + ret = -1; + } + break; + } + + if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) + continue; + +#ifdef _BSD_SOURCE + if (dent->d_type == DT_DIR) { + if ((ret = rm_r(dent->d_name)) == -1) + break; + continue; + } else if (dent->d_type == DT_UNKNOWN) +#endif + { + struct stat st; + if ((ret = lstat(dent->d_name, &st)) == -1) { + opkg_perror(ERROR, "Failed to lstat %s", + dent->d_name); + break; + } + if (S_ISDIR(st.st_mode)) { + if ((ret = rm_r(dent->d_name)) == -1) + break; + continue; + } + } + + if ((ret = unlink(dent->d_name)) == -1) { + opkg_perror(ERROR, "Failed to unlink %s", dent->d_name); + break; + } + } + + if (chdir("..") == -1) { + ret = -1; + opkg_perror(ERROR, "Failed to change to dir %s/..", path); + } + + if (rmdir(path) == -1 ) { + ret = -1; + opkg_perror(ERROR, "Failed to remove dir %s", path); + } + + if (closedir(dir) == -1) { + ret = -1; + opkg_perror(ERROR, "Failed to close dir %s", path); + } + + return ret; +} diff --git a/src/libopkg/file_util.h b/src/libopkg/file_util.h new file mode 100644 index 0000000..cfad551 --- /dev/null +++ b/src/libopkg/file_util.h @@ -0,0 +1,31 @@ +/* file_util.h - convenience routines for common file operations + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef FILE_UTIL_H +#define FILE_UTIL_H + +int file_exists(const char *file_name); +int file_is_dir(const char *file_name); +char *file_read_line_alloc(FILE *file); +int file_move(const char *src, const char *dest); +int file_copy(const char *src, const char *dest); +int file_mkdir_hier(const char *path, long mode); +char *file_md5sum_alloc(const char *file_name); +char *file_sha256sum_alloc(const char *file_name); +int rm_r(const char *path); + +#endif diff --git a/src/libopkg/hash_table.c b/src/libopkg/hash_table.c new file mode 100644 index 0000000..37b53e9 --- /dev/null +++ b/src/libopkg/hash_table.c @@ -0,0 +1,215 @@ +/* hash.c - hash tables for opkg + + Steven M. Ayer, Jamey Hicks + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "hash_table.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + + +static unsigned long +djb2_hash(const unsigned char *str) +{ + unsigned long hash = 5381; + int c; + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + return hash; +} + +static int +hash_index(hash_table_t *hash, const char *key) +{ + return djb2_hash((const unsigned char *)key) % hash->n_buckets; +} + +/* + * this is an open table keyed by strings + */ +void +hash_table_init(const char *name, hash_table_t *hash, int len) +{ + if (hash->entries != NULL) { + opkg_msg(ERROR, "Internal error: non empty hash table.\n"); + return; + } + + memset(hash, 0, sizeof(hash_table_t)); + + hash->name = name; + hash->n_buckets = len; + hash->entries = xcalloc(hash->n_buckets, sizeof(hash_entry_t)); +} + +void +hash_print_stats(hash_table_t *hash) +{ + printf("hash_table: %s, %d bytes\n" + "\tn_buckets=%d, n_elements=%d, n_collisions=%d\n" + "\tmax_bucket_len=%d, n_used_buckets=%d, ave_bucket_len=%.2f\n" + "\tn_hits=%d, n_misses=%d\n", + hash->name, + hash->n_buckets*(int)sizeof(hash_entry_t), + hash->n_buckets, + hash->n_elements, + hash->n_collisions, + hash->max_bucket_len, + hash->n_used_buckets, + (hash->n_used_buckets ? + ((float)hash->n_elements)/hash->n_used_buckets : 0.0f), + hash->n_hits, + hash->n_misses); +} + +void hash_table_deinit(hash_table_t *hash) +{ + int i; + if (!hash) + return; + + /* free the reminaing entries */ + for (i = 0; i < hash->n_buckets; i++) { + hash_entry_t *hash_entry = (hash->entries + i); + free (hash_entry->key); + /* skip the first entry as this is part of the array */ + hash_entry = hash_entry->next; + while (hash_entry) + { + hash_entry_t *old = hash_entry; + hash_entry = hash_entry->next; + free (old->key); + free (old); + } + } + + free (hash->entries); + + hash->entries = NULL; + hash->n_buckets = 0; +} + +void *hash_table_get(hash_table_t *hash, const char *key) +{ + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + while (hash_entry) + { + if (hash_entry->key) + { + if (strcmp(key, hash_entry->key) == 0) { + hash->n_hits++; + return hash_entry->data; + } + } + hash_entry = hash_entry->next; + } + hash->n_misses++; + return NULL; +} + +int hash_table_insert(hash_table_t *hash, const char *key, void *value) +{ + int bucket_len = 0; + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + if (hash_entry->key) { + if (strcmp(hash_entry->key, key) == 0) { + /* alread in table, update the value */ + hash_entry->data = value; + return 0; + } else { + /* + * if this is a collision, we have to go to the end of the ll, + * then add a new entry + * before we can hook up the value + */ + while (hash_entry->next) { + hash_entry = hash_entry->next; + if (strcmp(hash_entry->key, key) == 0) { + hash_entry->data = value; + return 0; + } + bucket_len++; + } + hash_entry->next = xcalloc(1, sizeof(hash_entry_t)); + hash_entry = hash_entry->next; + hash_entry->next = NULL; + + hash->n_collisions++; + if (++bucket_len > hash->max_bucket_len) + hash->max_bucket_len = bucket_len; + } + } else + hash->n_used_buckets++; + + hash->n_elements++; + hash_entry->key = xstrdup(key); + hash_entry->data = value; + + return 0; +} + +int hash_table_remove(hash_table_t *hash, const char *key) +{ + int ndx= hash_index(hash, key); + hash_entry_t *hash_entry = hash->entries + ndx; + hash_entry_t *next_entry=NULL, *last_entry=NULL; + while (hash_entry) + { + if (hash_entry->key) + { + if (strcmp(key, hash_entry->key) == 0) { + free(hash_entry->key); + if (last_entry) { + last_entry->next = hash_entry->next; + free(hash_entry); + } else { + next_entry = hash_entry->next; + if (next_entry) { + memmove(hash_entry, next_entry, sizeof(hash_entry_t)); + free(next_entry); + } else { + memset(hash_entry, 0 , sizeof(hash_entry_t)); + } + } + return 1; + } + } + last_entry = hash_entry; + hash_entry = hash_entry->next; + } + return 0; +} + +void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data) +{ + int i; + if (!hash || !f) + return; + + for (i = 0; i < hash->n_buckets; i++) { + hash_entry_t *hash_entry = (hash->entries + i); + do { + if(hash_entry->key) { + f(hash_entry->key, hash_entry->data, data); + } + } while((hash_entry = hash_entry->next)); + } +} + diff --git a/src/libopkg/hash_table.h b/src/libopkg/hash_table.h new file mode 100644 index 0000000..472b3e2 --- /dev/null +++ b/src/libopkg/hash_table.h @@ -0,0 +1,51 @@ +/* hash.h - hash tables for opkg + + Steven M. Ayer, Jamey Hicks + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef _HASH_TABLE_H_ +#define _HASH_TABLE_H_ + +typedef struct hash_entry hash_entry_t; +typedef struct hash_table hash_table_t; + +struct hash_entry { + char * key; + void * data; + struct hash_entry * next; +}; + +struct hash_table { + const char *name; + hash_entry_t * entries; + unsigned int n_buckets; + unsigned int n_elements; + + /* useful stats */ + unsigned int n_used_buckets; + unsigned int n_collisions; + unsigned int max_bucket_len; + unsigned int n_hits, n_misses; +}; + +void hash_table_init(const char *name, hash_table_t *hash, int len); +void hash_table_deinit(hash_table_t *hash); +void hash_print_stats(hash_table_t *hash); +void *hash_table_get(hash_table_t *hash, const char *key); +int hash_table_insert(hash_table_t *hash, const char *key, void *value); +int hash_table_remove(hash_table_t *has, const char *key); +void hash_table_foreach(hash_table_t *hash, void (*f)(const char *key, void *entry, void *data), void *data); + +#endif /* _HASH_TABLE_H_ */ diff --git a/src/libopkg/list.h b/src/libopkg/list.h new file mode 100644 index 0000000..c1325db --- /dev/null +++ b/src/libopkg/list.h @@ -0,0 +1,304 @@ +/* list.h - the opkg package management system + + Tick Chen <tick@openmoko.com> + + Copyright (C) 2008 Openmoko 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, 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. + + This is modified from Linux Kernel. +*/ + +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_POISON1 ((struct list_head *) 0x00100100) +#define LIST_POISON2 ((struct list_head *) 0x00200200) + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +static inline void __list_add(struct list_head *newitem, + struct list_head *prev, + struct list_head *next) { + next->prev = newitem; + newitem->next = next; + newitem->prev = prev; + prev->next = newitem; +} + +/** + * list_add - add a new entry + * @newitem: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *newitem, struct list_head *head) { + __list_add(newitem, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @newitem: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *newitem, struct list_head *head) { + __list_add(newitem, head->prev, head); +} + + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) { + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) { + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) { + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) { + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) { + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) { + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) { + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) { + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) { + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + + + +#define _offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - _offsetof(type,member) );}) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#endif diff --git a/src/libopkg/md5.c b/src/libopkg/md5.c new file mode 100644 index 0000000..2213dc1 --- /dev/null +++ b/src/libopkg/md5.c @@ -0,0 +1,455 @@ +/* Functions to compute MD5 message digest of files or memory blocks. + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995,1996,1997,1999,2000,2001,2005,2006,2008 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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, 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. */ + +/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ + +#include <config.h> + +#include "md5.h" + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef _LIBC +# include <endian.h> +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +# endif +/* We need to keep the namespace clean so define the MD5 function + protected using leading __ . */ +# define md5_init_ctx __md5_init_ctx +# define md5_process_block __md5_process_block +# define md5_process_bytes __md5_process_bytes +# define md5_finish_ctx __md5_finish_ctx +# define md5_read_ctx __md5_read_ctx +# define md5_stream __md5_stream +# define md5_buffer __md5_buffer +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (struct md5_ctx *ctx) +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Copy the 4 byte value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void +set_uint32 (char *cp, uint32_t v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. */ +void * +md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) +{ + char *r = resbuf; + set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A)); + set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B)); + set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C)); + set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D)); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +void * +md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) +{ + /* Take yet unprocessed bytes into account. */ + uint32_t bytes = ctx->buflen; + size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + ctx->buffer[size - 2] = SWAP (ctx->total[0] << 3); + ctx->buffer[size - 1] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + md5_process_block (ctx->buffer, size * 4, ctx); + + return md5_read_ctx (ctx, resbuf); +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +md5_stream (FILE *stream, void *resblock) +{ + struct md5_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + +process_partial_block: + + /* Process any remaining bytes. */ + if (sum > 0) + md5_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + md5_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (const char *buffer, size_t len, void *resblock) +{ + struct md5_ctx ctx; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return md5_finish_ctx (&ctx, resblock); +} + + +void +md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + md5_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + md5_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + uint32_t correct_words[16]; + const uint32_t *words = buffer; + size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t A = ctx->A; + uint32_t B = ctx->B; + uint32_t C = ctx->C; + uint32_t D = ctx->D; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + uint32_t *cwp = correct_words; + uint32_t A_save = A; + uint32_t B_save = B; + uint32_t C_save = C; + uint32_t D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + + Here is an equivalent invocation using Perl: + + perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}' + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/src/libopkg/md5.h b/src/libopkg/md5.h new file mode 100644 index 0000000..3ae657b --- /dev/null +++ b/src/libopkg/md5.h @@ -0,0 +1,118 @@ +/* Declaration of functions and data types used for MD5 sum computing + library functions. + Copyright (C) 1995-1997,1999,2000,2001,2004,2005,2006,2008 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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, 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. */ + +#ifndef _MD5_H +#define _MD5_H 1 + +#include <stdio.h> +#include <stdint.h> + +#define MD5_DIGEST_SIZE 16 +#define MD5_BLOCK_SIZE 64 + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#ifndef __THROW +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# else +# define __THROW +# endif +#endif + +#ifndef _LIBC +# define __md5_buffer md5_buffer +# define __md5_finish_ctx md5_finish_ctx +# define __md5_init_ctx md5_init_ctx +# define __md5_process_block md5_process_block +# define __md5_process_bytes md5_process_bytes +# define __md5_read_ctx md5_read_ctx +# define __md5_stream md5_stream +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; + + uint32_t total[2]; + uint32_t buflen; + uint32_t buffer[32]; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW; + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void __md5_process_block (const void *buffer, size_t len, + struct md5_ctx *ctx) __THROW; + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void __md5_process_bytes (const void *buffer, size_t len, + struct md5_ctx *ctx) __THROW; + +/* Process the remaining bytes in the buffer and put result from CTX + in first 16 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW; + + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW; + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +extern int __md5_stream (FILE *stream, void *resblock) __THROW; + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *__md5_buffer (const char *buffer, size_t len, + void *resblock) __THROW; + +#endif /* md5.h */ diff --git a/src/libopkg/nv_pair.c b/src/libopkg/nv_pair.c new file mode 100644 index 0000000..2728100 --- /dev/null +++ b/src/libopkg/nv_pair.c @@ -0,0 +1,39 @@ +/* nv_pair.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "nv_pair.h" +#include "libbb/libbb.h" + +int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value) +{ + + nv_pair->name = xstrdup(name); + nv_pair->value = xstrdup(value); + + return 0; +} + +void nv_pair_deinit(nv_pair_t *nv_pair) +{ + free(nv_pair->name); + nv_pair->name = NULL; + + free(nv_pair->value); + nv_pair->value = NULL; +} + + diff --git a/src/libopkg/nv_pair.h b/src/libopkg/nv_pair.h new file mode 100644 index 0000000..72513e4 --- /dev/null +++ b/src/libopkg/nv_pair.h @@ -0,0 +1,32 @@ +/* nv_pair.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef NV_PAIR_H +#define NV_PAIR_H + +typedef struct nv_pair nv_pair_t; +struct nv_pair +{ + char *name; + char *value; +}; + +int nv_pair_init(nv_pair_t *nv_pair, const char *name, const char *value); +void nv_pair_deinit(nv_pair_t *nv_pair); + +#endif + diff --git a/src/libopkg/nv_pair_list.c b/src/libopkg/nv_pair_list.c new file mode 100644 index 0000000..333e721 --- /dev/null +++ b/src/libopkg/nv_pair_list.c @@ -0,0 +1,98 @@ +/* nv_pair_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "nv_pair.h" +#include "void_list.h" +#include "nv_pair_list.h" +#include "libbb/libbb.h" + +void nv_pair_list_init(nv_pair_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void nv_pair_list_deinit(nv_pair_list_t *list) +{ + nv_pair_list_elt_t *pos; + nv_pair_t *nv_pair; + + while(!void_list_empty(list)) { + pos = nv_pair_list_pop(list); + if (!pos) + break; + nv_pair = (nv_pair_t *) pos->data; + nv_pair_deinit(nv_pair); + /* malloced in nv_pair_list_append */ + free(nv_pair); + pos->data = NULL; + free(pos); + } + void_list_deinit((void_list_t *) list); +} + +nv_pair_t *nv_pair_list_append(nv_pair_list_t *list, const char *name, const char *value) +{ + /* freed in nv_pair_list_deinit */ + nv_pair_t *nv_pair = xcalloc(1, sizeof(nv_pair_t)); + nv_pair_init(nv_pair, name, value); + void_list_append((void_list_t *) list, nv_pair); + + return nv_pair; +} + +void nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list) +{ + return (nv_pair_list_elt_t *) void_list_pop((void_list_t *) list); +} + +char *nv_pair_list_find(nv_pair_list_t *list, char *name) +{ + nv_pair_list_elt_t *iter; + nv_pair_t *nv_pair; + + list_for_each_entry(iter, &list->head, node) { + nv_pair = (nv_pair_t *)iter->data; + if (strcmp(nv_pair->name, name) == 0) { + return nv_pair->value; + } + } + return NULL; +} + +nv_pair_list_elt_t *nv_pair_list_first(nv_pair_list_t *list) { + return (nv_pair_list_elt_t * )void_list_first((void_list_t *) list); +} + +nv_pair_list_elt_t *nv_pair_list_prev(nv_pair_list_t *list, nv_pair_list_elt_t *node) { + return (nv_pair_list_elt_t * )void_list_prev((void_list_t *) list, (void_list_elt_t *)node); +} + +nv_pair_list_elt_t *nv_pair_list_next(nv_pair_list_t *list, nv_pair_list_elt_t *node) { + return (nv_pair_list_elt_t * )void_list_next((void_list_t *) list, (void_list_elt_t *)node); +} + +nv_pair_list_elt_t *nv_pair_list_last(nv_pair_list_t *list) { + return (nv_pair_list_elt_t * )void_list_last((void_list_t *) list); +} + + + diff --git a/src/libopkg/nv_pair_list.h b/src/libopkg/nv_pair_list.h new file mode 100644 index 0000000..1223a1f --- /dev/null +++ b/src/libopkg/nv_pair_list.h @@ -0,0 +1,48 @@ +/* nv_pair_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef NV_PAIR_LIST_H +#define NV_PAIR_LIST_H + +#include "nv_pair.h" +#include "void_list.h" + +typedef struct void_list_elt nv_pair_list_elt_t; + +typedef struct void_list nv_pair_list_t; + +static inline int nv_pair_list_empty(nv_pair_list_t *list) +{ + return void_list_empty ((void_list_t *)list); +} + +void nv_pair_list_init(nv_pair_list_t *list); +void nv_pair_list_deinit(nv_pair_list_t *list); + +nv_pair_t *nv_pair_list_append(nv_pair_list_t *list, + const char *name, const char *value); +void nv_pair_list_push(nv_pair_list_t *list, nv_pair_t *data); +nv_pair_list_elt_t *nv_pair_list_pop(nv_pair_list_t *list); +char *nv_pair_list_find(nv_pair_list_t *list, char *name); + +nv_pair_list_elt_t *nv_pair_list_first(nv_pair_list_t *list); +nv_pair_list_elt_t *nv_pair_list_prev(nv_pair_list_t *list, nv_pair_list_elt_t *node); +nv_pair_list_elt_t *nv_pair_list_next(nv_pair_list_t *list, nv_pair_list_elt_t *node); +nv_pair_list_elt_t *nv_pair_list_last(nv_pair_list_t *list); + +#endif + diff --git a/src/libopkg/opkg.c b/src/libopkg/opkg.c new file mode 100644 index 0000000..92f61f4 --- /dev/null +++ b/src/libopkg/opkg.c @@ -0,0 +1,872 @@ +/* opkg.c - the opkg package management system + + Thomas Wood <thomas@openedhand.com> + + Copyright (C) 2008 OpenMoko 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, 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. + */ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <fnmatch.h> + +#include "opkg.h" +#include "opkg_conf.h" + +#include "opkg_install.h" +#include "opkg_configure.h" +#include "opkg_download.h" +#include "opkg_remove.h" +#include "opkg_upgrade.h" + +#include "sprintf_alloc.h" +#include "file_util.h" + +#include <libbb/libbb.h> + +#define opkg_assert(expr) if (!(expr)) { \ + printf ("opkg: file %s: line %d (%s): Assertation '%s' failed",\ + __FILE__, __LINE__, __PRETTY_FUNCTION__, # expr); abort (); } + +#define progress(d, p) d.percentage = p; if (progress_callback) progress_callback (&d, user_data); + +/** Private Functions ***/ + +static int +opkg_configure_packages(char *pkg_name) +{ + pkg_vec_t *all; + int i; + pkg_t *pkg; + int r, err = 0; + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + for (i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + + if (pkg->state_status == SS_UNPACKED) { + r = opkg_configure(pkg); + if (r == 0) { + pkg->state_status = SS_INSTALLED; + pkg->parent->state_status = SS_INSTALLED; + pkg->state_flag &= ~SF_PREFER; + } else { + if (!err) + err = r; + } + } + } + + pkg_vec_free(all); + return err; +} + +struct _curl_cb_data { + opkg_progress_callback_t cb; + opkg_progress_data_t *progress_data; + void *user_data; + int start_range; + int finish_range; +}; + +int +curl_progress_cb(struct _curl_cb_data *cb_data, double t, /* dltotal */ + double d, /* dlnow */ + double ultotal, double ulnow) +{ + int p = (t) ? d * 100 / t : 0; + static int prev = -1; + int progress = 0; + + /* prevent the same value being sent twice (can occur due to rounding) */ + if (p == prev) + return 0; + prev = p; + + if (t < 1) + return 0; + + progress = cb_data->start_range + + (d / t * ((cb_data->finish_range - cb_data->start_range))); + cb_data->progress_data->percentage = progress; + + (cb_data->cb) (cb_data->progress_data, cb_data->user_data); + + return 0; +} + + +static struct opkg_conf saved_conf; +/*** Public API ***/ + +int +opkg_new() +{ + saved_conf = *conf; + + if (opkg_conf_init()) + goto err0; + + if (opkg_conf_load()) + goto err0; + + if (pkg_hash_load_feeds()) + goto err1; + + if (pkg_hash_load_status_files()) + goto err1; + + return 0; + +err1: + pkg_hash_deinit(); +err0: + opkg_conf_deinit(); + return -1; +} + +void +opkg_free(void) +{ +#ifdef HAVE_CURL + opkg_curl_cleanup(); +#endif + opkg_conf_deinit(); +} + +int +opkg_re_read_config_files(void) +{ + opkg_free(); + *conf = saved_conf; + return opkg_new(); +} + +int +opkg_get_option(char *option, void *value) +{ + int i; + extern opkg_option_t options[]; + + opkg_assert(option != NULL); + opkg_assert(value != NULL); + + *(char**)value = NULL; + + for (i=0; options[i].name; i++) { + if (strcmp(options[i].name, option) == 0) + break; + } + + if (options[i].name == NULL) + /* Not found. */ + return -1; + + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + *(int *)value = *(int *)options[i].value; + break; + + case OPKG_OPT_TYPE_INT: + *(int *)value = *(int *)options[i].value; + break; + + case OPKG_OPT_TYPE_STRING: + *(char **)value = xstrdup(*(char **)options[i].value); + break; + } + + return 0; +} + +void +opkg_set_option(char *option, void *value) +{ + int i; + extern opkg_option_t options[]; + + opkg_assert(option != NULL); + opkg_assert(value != NULL); + + for (i=0; options[i].name; i++) { + if (strcmp(options[i].name, option) == 0) + break; + } + + if (options[i].name == NULL) { + opkg_msg(ERROR, "Invalid option: %s\n", option); + return; + } + + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + if ((long)value == 0) + *((int *) options[i].value) = 0; + else + *((int *) options[i].value) = 1; + break; + + case OPKG_OPT_TYPE_INT: + *((int *) options[i].value) = (long)value; + break; + + case OPKG_OPT_TYPE_STRING: + *((char **) options[i].value) = xstrdup((char *)value); + break; + } + +} + +/** + * @brief libopkg API: Install package + * @param package_name The name of package in which is going to install + * @param progress_callback The callback function that report the status to caller. + */ +int +opkg_install_package(const char *package_name, + opkg_progress_callback_t progress_callback, + void *user_data) +{ + int err; + char *stripped_filename; + opkg_progress_data_t pdata; + pkg_t *old, *new; + pkg_vec_t *deps, *all; + int i, ndepends; + char **unresolved = NULL; + + opkg_assert(package_name != NULL); + + /* ... */ + pkg_info_preinstall_check(); + + + /* check to ensure package is not already installed */ + old = pkg_hash_fetch_installed_by_name(package_name); + if (old) { + opkg_msg(ERROR, "Package %s is already installed\n", + package_name); + return -1; + } + + new = pkg_hash_fetch_best_installation_candidate_by_name(package_name); + if (!new) { + opkg_msg(ERROR, "Couldn't find package %s\n", package_name); + return -1; + } + + new->state_flag |= SF_USER; + + pdata.action = -1; + pdata.pkg = new; + + progress(pdata, 0); + + /* find dependancies and download them */ + deps = pkg_vec_alloc(); + /* this function does not return the original package, so we insert it later */ + ndepends = pkg_hash_fetch_unsatisfied_dependencies(new, deps, + &unresolved); + if (unresolved) { + char **tmp = unresolved; + opkg_msg(ERROR, "Couldn't satisfy the following dependencies" + " for %s:\n", package_name); + while (*tmp) { + opkg_msg(ERROR, "\t%s", *tmp); + free(*tmp); + tmp++; + } + free(unresolved); + pkg_vec_free(deps); + opkg_message(ERROR, "\n"); + return -1; + } + + /* insert the package we are installing so that we download it */ + pkg_vec_insert(deps, new); + + /* download package and dependencies */ + for (i = 0; i < deps->len; i++) { + pkg_t *pkg; + struct _curl_cb_data cb_data; + char *url; + + pkg = deps->pkgs[i]; + if (pkg->local_filename) + continue; + + pdata.pkg = pkg; + pdata.action = OPKG_DOWNLOAD; + + if (pkg->src == NULL) { + opkg_msg(ERROR, "Package %s not available from any " + "configured src\n", package_name); + return -1; + } + + sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename); + + /* Get the filename part, without any directory */ + stripped_filename = strrchr(pkg->filename, '/'); + if (!stripped_filename) + stripped_filename = pkg->filename; + + sprintf_alloc(&pkg->local_filename, "%s/%s", conf->tmp_dir, + stripped_filename); + + cb_data.cb = progress_callback; + cb_data.progress_data = &pdata; + cb_data.user_data = user_data; + /* 75% of "install" progress is for downloading */ + cb_data.start_range = 75 * i / deps->len; + cb_data.finish_range = 75 * (i + 1) / deps->len; + + err = opkg_download(url, pkg->local_filename, + (curl_progress_func) curl_progress_cb, + &cb_data, 0); + free(url); + + if (err) { + pkg_vec_free(deps); + return -1; + } + + } + pkg_vec_free(deps); + + /* clear depenacy checked marks, left by pkg_hash_fetch_unsatisfied_dependencies */ + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + for (i = 0; i < all->len; i++) { + all->pkgs[i]->parent->dependencies_checked = 0; + } + pkg_vec_free(all); + + + /* 75% of "install" progress is for downloading */ + pdata.pkg = new; + pdata.action = OPKG_INSTALL; + progress(pdata, 75); + + /* unpack the package */ + err = opkg_install_pkg(new, 0); + + if (err) { + return -1; + } + + progress(pdata, 75); + + /* run configure scripts, etc. */ + err = opkg_configure_packages(NULL); + if (err) { + return -1; + } + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + progress(pdata, 100); + return 0; +} + +int +opkg_remove_package(const char *package_name, + opkg_progress_callback_t progress_callback, void *user_data) +{ + int err; + pkg_t *pkg = NULL; + pkg_t *pkg_to_remove; + opkg_progress_data_t pdata; + + opkg_assert(package_name != NULL); + + pkg_info_preinstall_check(); + + pkg = pkg_hash_fetch_installed_by_name(package_name); + + if (pkg == NULL || pkg->state_status == SS_NOT_INSTALLED) { + opkg_msg(ERROR, "Package %s not installed\n", package_name); + return -1; + } + + pdata.action = OPKG_REMOVE; + pdata.pkg = pkg; + progress(pdata, 0); + + if (conf->restrict_to_default_dest) { + pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(pkg->name, + conf->default_dest); + } else { + pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name); + } + + + progress(pdata, 75); + + err = opkg_remove_pkg(pkg_to_remove, 0); + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + + progress(pdata, 100); + return (err) ? -1 : 0; +} + +int +opkg_upgrade_package(const char *package_name, + opkg_progress_callback_t progress_callback, + void *user_data) +{ + int err; + pkg_t *pkg; + opkg_progress_data_t pdata; + + opkg_assert(package_name != NULL); + + pkg_info_preinstall_check(); + + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(package_name, + conf->default_dest); + } else { + pkg = pkg_hash_fetch_installed_by_name(package_name); + } + + if (!pkg) { + opkg_msg(ERROR, "Package %s not installed\n", package_name); + return -1; + } + + pdata.action = OPKG_INSTALL; + pdata.pkg = pkg; + progress(pdata, 0); + + err = opkg_upgrade_pkg(pkg); + if (err) { + return -1; + } + progress(pdata, 75); + + err = opkg_configure_packages(NULL); + if (err) { + return -1; + } + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + progress(pdata, 100); + return 0; +} + +int +opkg_upgrade_all(opkg_progress_callback_t progress_callback, void *user_data) +{ + pkg_vec_t *installed; + int err = 0; + int i; + pkg_t *pkg; + opkg_progress_data_t pdata; + + pdata.action = OPKG_INSTALL; + pdata.pkg = NULL; + + progress(pdata, 0); + + installed = pkg_vec_alloc(); + pkg_info_preinstall_check(); + + pkg_hash_fetch_all_installed(installed); + for (i = 0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + + pdata.pkg = pkg; + progress(pdata, 99 * i / installed->len); + + err += opkg_upgrade_pkg(pkg); + } + pkg_vec_free(installed); + + if (err) + return 1; + + err = opkg_configure_packages(NULL); + if (err) + return 1; + + /* write out status files and file lists */ + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + + pdata.pkg = NULL; + progress(pdata, 100); + return 0; +} + +int +opkg_update_package_lists(opkg_progress_callback_t progress_callback, + void *user_data) +{ + char *tmp; + int err, result = 0; + char *lists_dir; + pkg_src_list_elt_t *iter; + pkg_src_t *src; + int sources_list_count, sources_done; + opkg_progress_data_t pdata; + + pdata.action = OPKG_DOWNLOAD; + pdata.pkg = NULL; + progress(pdata, 0); + + sprintf_alloc(&lists_dir, "%s", (conf->restrict_to_default_dest) + ? conf->default_dest->lists_dir : conf->lists_dir); + + if (!file_is_dir(lists_dir)) { + if (file_exists(lists_dir)) { + opkg_msg(ERROR, "%s is not a directory\n", lists_dir); + free(lists_dir); + return 1; + } + + err = file_mkdir_hier(lists_dir, 0755); + if (err) { + opkg_msg(ERROR, "Couldn't create lists_dir %s\n", + lists_dir); + free(lists_dir); + return 1; + } + } + + sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir); + if (mkdtemp(tmp) == NULL) { + opkg_perror(ERROR, "Coundn't create temporary directory %s", + tmp); + free(lists_dir); + free(tmp); + return 1; + } + + /* count the number of sources so we can give some progress updates */ + sources_list_count = 0; + sources_done = 0; + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + sources_list_count++; + } + + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + char *url, *list_file_name = NULL; + + src = (pkg_src_t *) iter->data; + + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, + src->extra_data, + src->gzip ? "Packages.gz" : "Packages"); + else + sprintf_alloc(&url, "%s/%s", src->value, + src->gzip ? "Packages.gz" : "Packages"); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + if (src->gzip) { + FILE *in, *out; + struct _curl_cb_data cb_data; + char *tmp_file_name = NULL; + + sprintf_alloc(&tmp_file_name, "%s/%s.gz", tmp, + src->name); + + opkg_msg(INFO, "Downloading %s to %s...\n", url, + tmp_file_name); + + cb_data.cb = progress_callback; + cb_data.progress_data = &pdata; + cb_data.user_data = user_data; + cb_data.start_range = + 100 * sources_done / sources_list_count; + cb_data.finish_range = + 100 * (sources_done + 1) / sources_list_count; + + err = opkg_download(url, tmp_file_name, + (curl_progress_func) curl_progress_cb, + &cb_data, 0); + + if (err == 0) { + opkg_msg(INFO, "Inflating %s...\n", + tmp_file_name); + in = fopen(tmp_file_name, "r"); + out = fopen(list_file_name, "w"); + if (in && out) + unzip(in, out); + else + err = 1; + if (in) + fclose(in); + if (out) + fclose(out); + unlink(tmp_file_name); + } + free(tmp_file_name); + } else + err = opkg_download(url, list_file_name, NULL, NULL, 0); + + if (err) { + opkg_msg(ERROR, "Couldn't retrieve %s\n", url); + result = -1; + } + free(url); + +#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + if (conf->check_signature) { + char *sig_file_name; + /* download detached signitures to verify the package lists */ + /* get the url for the sig file */ + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, + src->extra_data, "Packages.sig"); + else + sprintf_alloc(&url, "%s/%s", src->value, + "Packages.sig"); + + /* create filename for signature */ + sprintf_alloc(&sig_file_name, "%s/%s.sig", lists_dir, + src->name); + + /* make sure there is no existing signature file */ + unlink(sig_file_name); + + err = opkg_download(url, sig_file_name, NULL, NULL, 0); + if (err) { + opkg_msg(ERROR, "Couldn't retrieve %s\n", url); + } else { + int err; + err = opkg_verify_file(list_file_name, + sig_file_name); + if (err == 0) { + opkg_msg(INFO, "Signature check " + "passed for %s", + list_file_name); + } else { + opkg_msg(ERROR, "Signature check " + "failed for %s", + list_file_name); + } + } + free(sig_file_name); + free(url); + } +#else + opkg_msg(INFO, "Signature check skipped for %s as GPG support" + " has not been enabled in this build\n", + list_file_name); +#endif + free(list_file_name); + + sources_done++; + progress(pdata, 100 * sources_done / sources_list_count); + } + + rmdir(tmp); + free(tmp); + free(lists_dir); + + /* Now re-read the package lists to update package hash tables. */ + opkg_re_read_config_files(); + + return result; +} + +static int +pkg_compare_names_and_version(const void *a0, const void *b0) +{ + const pkg_t *a = *(const pkg_t **)a0; + const pkg_t *b = *(const pkg_t **)b0; + int ret; + + ret = strcmp(a->name, b->name); + + if (ret == 0) + ret = pkg_compare_versions(a, b); + + return ret; +} + +int +opkg_list_packages(opkg_package_callback_t callback, void *user_data) +{ + pkg_vec_t *all; + int i; + + opkg_assert(callback); + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + pkg_vec_sort(all, pkg_compare_names_and_version); + + for (i = 0; i < all->len; i++) { + pkg_t *pkg; + + pkg = all->pkgs[i]; + + callback(pkg, user_data); + } + + pkg_vec_free(all); + + return 0; +} + +int +opkg_list_upgradable_packages(opkg_package_callback_t callback, void *user_data) +{ + struct active_list *head; + struct active_list *node; + pkg_t *old = NULL, *new = NULL; + + opkg_assert(callback); + + /* ensure all data is valid */ + pkg_info_preinstall_check(); + + head = prepare_upgrade_list(); + for (node = active_list_next(head, head); node; + node = active_list_next(head, node)) { + old = list_entry(node, pkg_t, list); + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + if (new == NULL) + continue; + callback(new, user_data); + } + active_list_head_delete(head); + return 0; +} + +pkg_t * +opkg_find_package(const char *name, const char *ver, const char *arch, + const char *repo) +{ + int pkg_found = 0; + pkg_t *pkg = NULL; + pkg_vec_t *all; + int i; +#define sstrcmp(x,y) (x && y) ? strcmp (x, y) : 0 + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + for (i = 0; i < all->len; i++) { + char *pkgv; + + pkg = all->pkgs[i]; + + /* check name */ + if (sstrcmp(pkg->name, name)) + continue; + + /* check version */ + pkgv = pkg_version_str_alloc(pkg); + if (sstrcmp(pkgv, ver)) { + free(pkgv); + continue; + } + free(pkgv); + + /* check architecture */ + if (arch) { + if (sstrcmp(pkg->architecture, arch)) + continue; + } + + /* check repository */ + if (repo) { + if (sstrcmp(pkg->src->name, repo)) + continue; + } + + /* match found */ + pkg_found = 1; + break; + } + + pkg_vec_free(all); + + return pkg_found ? pkg : NULL; +} + +/** + * @brief Check the accessibility of repositories. + * @return return how many repositories cannot access. 0 means all okay. + */ +int +opkg_repository_accessibility_check(void) +{ + pkg_src_list_elt_t *iter; + str_list_elt_t *iter1; + str_list_t *src; + int repositories = 0; + int ret = 0; + char *repo_ptr; + char *stmp; + char *host, *end; + + src = str_list_alloc(); + + list_for_each_entry(iter, &conf->pkg_src_list.head, node) { + host = strstr(((pkg_src_t *)iter->data)->value, "://") + 3; + end = index(host, '/'); + if (strstr(((pkg_src_t *) iter->data)->value, "://") && end) + stmp = xstrndup(((pkg_src_t *) iter->data)->value, + end - ((pkg_src_t *) iter->data)->value); + else + stmp = xstrdup(((pkg_src_t *) iter->data)->value); + + for (iter1 = str_list_first(src); iter1; + iter1 = str_list_next(src, iter1)) { + if (strstr(iter1->data, stmp)) + break; + } + if (iter1) + continue; + + sprintf_alloc(&repo_ptr, "%s/index.html", stmp); + free(stmp); + + str_list_append(src, repo_ptr); + free(repo_ptr); + repositories++; + } + + while (repositories > 0) { + iter1 = str_list_pop(src); + repositories--; + + if (opkg_download(iter1->data, "/dev/null", NULL, NULL, 0)) + ret++; + str_list_elt_deinit(iter1); + } + + free(src); + + return ret; +} diff --git a/src/libopkg/opkg.h b/src/libopkg/opkg.h new file mode 100644 index 0000000..4fbd404 --- /dev/null +++ b/src/libopkg/opkg.h @@ -0,0 +1,61 @@ +/* opkg.h - the opkg package management system + + Thomas Wood <thomas@openedhand.com> + + Copyright (C) 2008 OpenMoko 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, 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. +*/ + +#ifndef OPKG_H +#define OPKG_H + +#include "pkg.h" +#include "opkg_message.h" + +typedef struct _opkg_progress_data_t opkg_progress_data_t; + +typedef void (*opkg_progress_callback_t) (const opkg_progress_data_t *progress, void *user_data); +typedef void (*opkg_package_callback_t) (pkg_t *pkg, void *user_data); + +enum _opkg_action_t +{ + OPKG_INSTALL, + OPKG_REMOVE, + OPKG_DOWNLOAD +}; + +struct _opkg_progress_data_t +{ + int percentage; + int action; + pkg_t *pkg; +}; + +int opkg_new (void); +void opkg_free (void); +int opkg_re_read_config_files (void); +int opkg_get_option (char *option, void *value); +void opkg_set_option (char *option, void *value); + +int opkg_install_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_remove_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_upgrade_package (const char *package_name, opkg_progress_callback_t callback, void *user_data); +int opkg_upgrade_all (opkg_progress_callback_t callback, void *user_data); +int opkg_update_package_lists (opkg_progress_callback_t callback, void *user_data); + +int opkg_list_packages (opkg_package_callback_t callback, void *user_data); +int opkg_list_upgradable_packages (opkg_package_callback_t callback, void *user_data); +pkg_t* opkg_find_package (const char *name, const char *version, const char *architecture, const char *repository); + +int opkg_repository_accessibility_check(void); + +#endif /* OPKG_H */ diff --git a/src/libopkg/opkg_cmd.c b/src/libopkg/opkg_cmd.c new file mode 100644 index 0000000..11e7867 --- /dev/null +++ b/src/libopkg/opkg_cmd.c @@ -0,0 +1,1319 @@ +/* opkg_cmd.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <dirent.h> +#include <glob.h> +#include <fnmatch.h> +#include <signal.h> +#include <unistd.h> + +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "opkg_message.h" +#include "release.h" +#include "pkg.h" +#include "pkg_dest.h" +#include "pkg_parse.h" +#include "sprintf_alloc.h" +#include "pkg.h" +#include "file_util.h" +#include "libbb/libbb.h" +#include "opkg_utils.h" +#include "opkg_defines.h" +#include "opkg_download.h" +#include "opkg_install.h" +#include "opkg_upgrade.h" +#include "opkg_remove.h" +#include "opkg_configure.h" +#include "xsystem.h" + +static void +print_pkg(pkg_t *pkg) +{ + char *version = pkg_version_str_alloc(pkg); + if (pkg->description) + printf("%s - %s - %s\n", pkg->name, version, pkg->description); + else + printf("%s - %s\n", pkg->name, version); + free(version); +} + +int opkg_state_changed; + +static void +write_status_files_if_changed(void) +{ + if (opkg_state_changed && !conf->noaction) { + opkg_msg(INFO, "Writing status file.\n"); + opkg_conf_write_status_files(); + pkg_write_changed_filelists(); + sync(); + } else { + opkg_msg(DEBUG, "Nothing to be done.\n"); + } +} + +static void +sigint_handler(int sig) +{ + signal(sig, SIG_DFL); + opkg_msg(NOTICE, "Interrupted. Writing out status database.\n"); + write_status_files_if_changed(); + exit(128 + sig); +} + +static int +opkg_update_cmd(int argc, char **argv) +{ + char *tmp; + int err; + int failures; + char *lists_dir; + pkg_src_list_elt_t *iter; + pkg_src_t *src; + + + sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir); + + if (! file_is_dir(lists_dir)) { + if (file_exists(lists_dir)) { + opkg_msg(ERROR, "%s exists, but is not a directory.\n", + lists_dir); + free(lists_dir); + return -1; + } + err = file_mkdir_hier(lists_dir, 0755); + if (err) { + free(lists_dir); + return -1; + } + } + + failures = 0; + + sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir); + if (mkdtemp (tmp) == NULL) { + opkg_perror(ERROR, "Failed to make temp dir %s", conf->tmp_dir); + return -1; + } + + + for (iter = void_list_first(&conf->dist_src_list); iter; iter = void_list_next(&conf->dist_src_list, iter)) { + char *url, *list_file_name; + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&url, "%s/dists/%s/Release", src->value, src->name); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + err = opkg_download(url, list_file_name, NULL, NULL, 0); + if (!err) { + opkg_msg(NOTICE, "Downloaded release files for dist %s.\n", + src->name); + release_t *release = release_new(); + err = release_init_from_file(release, list_file_name); + if (!err) { + if (!release_comps_supported(release, src->extra_data)) + err = -1; + } + if (!err) { + err = release_download(release, src, lists_dir, tmp); + } + release_deinit(release); + if (err) + unlink(list_file_name); + } + + if (err) + failures++; + + free(list_file_name); + free(url); + } + + for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) { + char *url, *list_file_name; + + src = (pkg_src_t *)iter->data; + + if (src->extra_data && !strcmp(src->extra_data, "__dummy__ ")) + continue; + + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, + src->gzip ? "Packages.gz" : "Packages"); + else + sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages"); + + sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name); + if (src->gzip) { + char *tmp_file_name; + FILE *in, *out; + + sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name); + err = opkg_download(url, tmp_file_name, NULL, NULL, 0); + if (err == 0) { + opkg_msg(NOTICE, "Inflating %s.\n", url); + in = fopen (tmp_file_name, "r"); + out = fopen (list_file_name, "w"); + if (in && out) + unzip (in, out); + else + err = 1; + if (in) + fclose (in); + if (out) + fclose (out); + unlink (tmp_file_name); + } + free(tmp_file_name); + } else + err = opkg_download(url, list_file_name, NULL, NULL, 0); + if (err) { + failures++; + } else { + opkg_msg(NOTICE, "Updated list of available packages in %s.\n", + list_file_name); + } + free(url); +#if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + if (conf->check_signature) { + /* download detached signitures to verify the package lists */ + /* get the url for the sig file */ + if (src->extra_data) /* debian style? */ + sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, + "Packages.sig"); + else + sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig"); + + /* create temporary file for it */ + char *tmp_file_name; + + /* Put the signature in the right place */ + sprintf_alloc (&tmp_file_name, "%s/%s.sig", lists_dir, src->name); + + err = opkg_download(url, tmp_file_name, NULL, NULL, 0); + if (err) { + failures++; + opkg_msg(NOTICE, "Signature check failed.\n"); + } else { + err = opkg_verify_file (list_file_name, tmp_file_name); + if (err == 0) + opkg_msg(NOTICE, "Signature check passed.\n"); + else + opkg_msg(NOTICE, "Signature check failed.\n"); + } + if (err) { + /* The signature was wrong so delete it */ + opkg_msg(NOTICE, "Remove wrong Signature file.\n"); + unlink (tmp_file_name); + unlink (list_file_name); + } + /* We shouldn't unlink the signature ! */ + // unlink (tmp_file_name); + free (tmp_file_name); + free (url); + } +#else + // Do nothing +#endif + free(list_file_name); + } + rmdir (tmp); + free (tmp); + free(lists_dir); + + return failures; +} + + +struct opkg_intercept +{ + char *oldpath; + char *statedir; +}; + +typedef struct opkg_intercept *opkg_intercept_t; + +static opkg_intercept_t +opkg_prep_intercepts(void) +{ + opkg_intercept_t ctx; + char *newpath; + + ctx = xcalloc(1, sizeof (*ctx)); + ctx->oldpath = xstrdup(getenv("PATH")); + sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath); + sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX", conf->tmp_dir); + + if (mkdtemp(ctx->statedir) == NULL) { + opkg_perror(ERROR,"Failed to make temp dir %s", ctx->statedir); + free(ctx->oldpath); + free(ctx->statedir); + free(newpath); + free(ctx); + return NULL; + } + + setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1); + setenv("PATH", newpath, 1); + free(newpath); + + return ctx; +} + +static int +opkg_finalize_intercepts(opkg_intercept_t ctx) +{ + DIR *dir; + int err = 0; + + setenv ("PATH", ctx->oldpath, 1); + free (ctx->oldpath); + + dir = opendir (ctx->statedir); + if (dir) { + struct dirent *de; + while (de = readdir (dir), de != NULL) { + char *path; + + if (de->d_name[0] == '.') + continue; + + sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name); + if (access (path, X_OK) == 0) { + const char *argv[] = {"sh", "-c", path, NULL}; + xsystem (argv); + } + free (path); + } + closedir(dir); + } else + opkg_perror(ERROR, "Failed to open dir %s", ctx->statedir); + + rm_r(ctx->statedir); + free (ctx->statedir); + free (ctx); + + return err; +} + +/* For package pkg do the following: If it is already visited, return. If not, + add it in visited list and recurse to its deps. Finally, add it to ordered + list. + pkg_vec all contains all available packages in repos. + pkg_vec visited contains packages already visited by this function, and is + used to end recursion and avoid an infinite loop on graph cycles. + pkg_vec ordered will finally contain the ordered set of packages. +*/ +static int +opkg_recurse_pkgs_in_order(pkg_t *pkg, pkg_vec_t *all, + pkg_vec_t *visited, pkg_vec_t *ordered) +{ + int j,k,l,m; + int count; + pkg_t *dep; + compound_depend_t * compound_depend; + depend_t ** possible_satisfiers; + abstract_pkg_t *abpkg; + abstract_pkg_t **dependents; + + /* If it's just an available package, that is, not installed and not even + unpacked, skip it */ + /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED + would do here. However, if there is an intermediate node (pkg) that is + configured and installed between two unpacked packages, the latter + won't be properly reordered, unless all installed/unpacked pkgs are + checked */ + if (pkg->state_status == SS_NOT_INSTALLED) + return 0; + + /* If the package has already been visited (by this function), skip it */ + for(j = 0; j < visited->len; j++) + if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) { + opkg_msg(DEBUG, "pkg %s already visited, skipping.\n", pkg->name); + return 0; + } + + pkg_vec_insert(visited, pkg); + + count = pkg->pre_depends_count + pkg->depends_count + \ + pkg->recommends_count + pkg->suggests_count; + + opkg_msg(DEBUG, "pkg %s.\n", pkg->name); + + /* Iterate over all the dependencies of pkg. For each one, find a package + that is either installed or unpacked and satisfies this dependency. + (there should only be one such package per dependency installed or + unpacked). Then recurse to the dependency package */ + for (j=0; j < count ; j++) { + compound_depend = &pkg->depends[j]; + possible_satisfiers = compound_depend->possibilities; + for (k=0; k < compound_depend->possibility_count ; k++) { + abpkg = possible_satisfiers[k]->pkg; + dependents = abpkg->provided_by->pkgs; + l = 0; + if (dependents != NULL) + while (l < abpkg->provided_by->len && dependents[l] != NULL) { + opkg_msg(DEBUG, "Descending on pkg %s.\n", + dependents [l]->name); + + /* find whether dependent l is installed or unpacked, + * and then find which package in the list satisfies it */ + for(m = 0; m < all->len; m++) { + dep = all->pkgs[m]; + if ( dep->state_status != SS_NOT_INSTALLED) + if ( ! strcmp(dep->name, dependents[l]->name)) { + opkg_recurse_pkgs_in_order(dep, all, + visited, ordered); + /* Stop the outer loop */ + l = abpkg->provided_by->len; + /* break from the inner loop */ + break; + } + } + l++; + } + } + } + + /* When all recursions from this node down, are over, and all + dependencies have been added in proper order in the ordered array, add + also the package pkg to ordered array */ + pkg_vec_insert(ordered, pkg); + + return 0; + +} + +static int +opkg_configure_packages(char *pkg_name) +{ + pkg_vec_t *all, *ordered, *visited; + int i; + pkg_t *pkg; + opkg_intercept_t ic; + int r, err = 0; + + if (conf->offline_root && !conf->force_postinstall) { + opkg_msg(INFO, "Offline root mode: not configuring unpacked packages.\n"); + return 0; + } + opkg_msg(INFO, "Configuring unpacked packages.\n"); + + all = pkg_vec_alloc(); + + pkg_hash_fetch_available(all); + + /* Reorder pkgs in order to be configured according to the Depends: tag + order */ + opkg_msg(INFO, "Reordering packages before configuring them...\n"); + ordered = pkg_vec_alloc(); + visited = pkg_vec_alloc(); + for(i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + opkg_recurse_pkgs_in_order(pkg, all, visited, ordered); + } + + ic = opkg_prep_intercepts(); + if (ic == NULL) { + err = -1; + goto error; + } + + for(i = 0; i < ordered->len; i++) { + pkg = ordered->pkgs[i]; + + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + + if (pkg->state_status == SS_UNPACKED) { + opkg_msg(NOTICE, "Configuring %s.\n", pkg->name); + r = opkg_configure(pkg); + if (r == 0) { + pkg->state_status = SS_INSTALLED; + pkg->parent->state_status = SS_INSTALLED; + pkg->state_flag &= ~SF_PREFER; + opkg_state_changed++; + } else { + err = -1; + } + } + } + + if (opkg_finalize_intercepts (ic)) + err = -1; + +error: + pkg_vec_free(all); + pkg_vec_free(ordered); + pkg_vec_free(visited); + + return err; +} + +static int +opkg_remove_cmd(int argc, char **argv); + +static int +opkg_install_cmd(int argc, char **argv) +{ + int i; + char *arg; + int err = 0; + + if (conf->force_reinstall) { + int saved_force_depends = conf->force_depends; + conf->force_depends = 1; + (void)opkg_remove_cmd(argc, argv); + conf->force_depends = saved_force_depends; + conf->force_reinstall = 0; + } + + signal(SIGINT, sigint_handler); + + /* + * Now scan through package names and install + */ + for (i=0; i < argc; i++) { + arg = argv[i]; + + opkg_msg(DEBUG2, "%s\n", arg); + if (opkg_prepare_url_for_install(arg, &argv[i])) + return -1; + } + pkg_info_preinstall_check(); + + for (i=0; i < argc; i++) { + arg = argv[i]; + if (opkg_install_by_name(arg)) { + opkg_msg(ERROR, "Cannot install package %s.\n", arg); + err = -1; + } + } + + if (opkg_configure_packages(NULL)) + err = -1; + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_upgrade_cmd(int argc, char **argv) +{ + int i; + pkg_t *pkg; + int err = 0; + + signal(SIGINT, sigint_handler); + + if (argc) { + for (i=0; i < argc; i++) { + char *arg = argv[i]; + + if (opkg_prepare_url_for_install(arg, &arg)) + return -1; + } + pkg_info_preinstall_check(); + + for (i=0; i < argc; i++) { + char *arg = argv[i]; + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(argv[i], + conf->default_dest); + if (pkg == NULL) { + opkg_msg(NOTICE, "Package %s not installed in %s.\n", + argv[i], conf->default_dest->name); + continue; + } + } else { + pkg = pkg_hash_fetch_installed_by_name(argv[i]); + } + if (pkg) { + if (opkg_upgrade_pkg(pkg)) + err = -1; + } else { + if (opkg_install_by_name(arg)) + err = -1; + } + } + } else { + pkg_vec_t *installed = pkg_vec_alloc(); + + pkg_info_preinstall_check(); + + pkg_hash_fetch_all_installed(installed); + for (i = 0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + if (opkg_upgrade_pkg(pkg)) + err = -1; + } + pkg_vec_free(installed); + } + + if (opkg_configure_packages(NULL)) + err = -1; + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_download_cmd(int argc, char **argv) +{ + int i, err = 0; + char *arg; + pkg_t *pkg; + + pkg_info_preinstall_check(); + for (i = 0; i < argc; i++) { + arg = argv[i]; + + pkg = pkg_hash_fetch_best_installation_candidate_by_name(arg); + if (pkg == NULL) { + opkg_msg(ERROR, "Cannot find package %s.\n", arg); + continue; + } + + if (opkg_download_pkg(pkg, ".")) + err = -1; + + if (err) { + opkg_msg(ERROR, "Failed to download %s.\n", pkg->name); + } else { + opkg_msg(NOTICE, "Downloaded %s as %s.\n", + pkg->name, pkg->local_filename); + } + } + + return err; +} + + +static int +opkg_list_cmd(int argc, char **argv) +{ + int i; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_available(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + print_pkg(pkg); + } + pkg_vec_free(available); + + return 0; +} + + +static int +opkg_list_installed_cmd(int argc, char **argv) +{ + int i ; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + print_pkg(pkg); + } + + pkg_vec_free(available); + + return 0; +} + +static int +opkg_list_changed_conffiles_cmd(int argc, char **argv) +{ + int i ; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + conffile_list_elt_t *iter; + conffile_t *cf; + + if (argc > 0) { + pkg_name = argv[0]; + } + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + pkg_vec_sort(available, pkg_compare_names); + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + /* if we have package name or pattern and pkg does not match, then skip it */ + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) + continue; + if (nv_pair_list_empty(&pkg->conffiles)) + continue; + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + cf = (conffile_t *)iter->data; + if (cf->name && cf->value && conffile_has_been_modified(cf)) + printf("%s\n", cf->name); + } + } + pkg_vec_free(available); + return 0; +} + +static int +opkg_list_upgradable_cmd(int argc, char **argv) +{ + struct active_list *head = prepare_upgrade_list(); + struct active_list *node=NULL; + pkg_t *_old_pkg, *_new_pkg; + char *old_v, *new_v; + for (node = active_list_next(head, head); node;node = active_list_next(head,node)) { + _old_pkg = list_entry(node, pkg_t, list); + _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(_old_pkg->name); + if (_new_pkg == NULL) + continue; + old_v = pkg_version_str_alloc(_old_pkg); + new_v = pkg_version_str_alloc(_new_pkg); + printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v); + free(old_v); + free(new_v); + } + active_list_head_delete(head); + return 0; +} + +static int +opkg_info_status_cmd(int argc, char **argv, int installed_only) +{ + int i; + pkg_vec_t *available; + pkg_t *pkg; + char *pkg_name = NULL; + + if (argc > 0) { + pkg_name = argv[0]; + } + + available = pkg_vec_alloc(); + if (installed_only) + pkg_hash_fetch_all_installed(available); + else + pkg_hash_fetch_available(available); + + for (i=0; i < available->len; i++) { + pkg = available->pkgs[i]; + if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) { + continue; + } + + pkg_formatted_info(stdout, pkg); + + if (conf->verbosity >= NOTICE) { + conffile_list_elt_t *iter; + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + conffile_t *cf = (conffile_t *)iter->data; + int modified = conffile_has_been_modified(cf); + if (cf->value) + opkg_msg(INFO, "conffile=%s md5sum=%s modified=%d.\n", + cf->name, cf->value, modified); + } + } + } + pkg_vec_free(available); + + return 0; +} + +static int +opkg_info_cmd(int argc, char **argv) +{ + return opkg_info_status_cmd(argc, argv, 0); +} + +static int +opkg_status_cmd(int argc, char **argv) +{ + return opkg_info_status_cmd(argc, argv, 1); +} + +static int +opkg_configure_cmd(int argc, char **argv) +{ + int err; + char *pkg_name = NULL; + + if (argc > 0) + pkg_name = argv[0]; + + err = opkg_configure_packages(pkg_name); + + write_status_files_if_changed(); + + return err; +} + +static int +opkg_remove_cmd(int argc, char **argv) +{ + int i, a, done, err = 0; + pkg_t *pkg; + pkg_t *pkg_to_remove; + pkg_vec_t *available; + + done = 0; + + signal(SIGINT, sigint_handler); + + pkg_info_preinstall_check(); + + available = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(available); + + for (i=0; i<argc; i++) { + for (a=0; a<available->len; a++) { + pkg = available->pkgs[a]; + if (fnmatch(argv[i], pkg->name, 0)) { + continue; + } + if (conf->restrict_to_default_dest) { + pkg_to_remove = pkg_hash_fetch_installed_by_name_dest( + pkg->name, + conf->default_dest); + } else { + pkg_to_remove = pkg_hash_fetch_installed_by_name(pkg->name); + } + + if (pkg_to_remove == NULL) { + opkg_msg(ERROR, "Package %s is not installed.\n", pkg->name); + continue; + } + if (pkg->state_status == SS_NOT_INSTALLED) { + opkg_msg(ERROR, "Package %s not installed.\n", pkg->name); + continue; + } + + if (opkg_remove_pkg(pkg_to_remove, 0)) + err = -1; + else + done = 1; + } + } + + pkg_vec_free(available); + + if (done == 0) + opkg_msg(NOTICE, "No packages removed.\n"); + + write_status_files_if_changed(); + return err; +} + +static int +opkg_flag_cmd(int argc, char **argv) +{ + int i; + pkg_t *pkg; + const char *flags = argv[0]; + + signal(SIGINT, sigint_handler); + + for (i=1; i < argc; i++) { + if (conf->restrict_to_default_dest) { + pkg = pkg_hash_fetch_installed_by_name_dest(argv[i], + conf->default_dest); + } else { + pkg = pkg_hash_fetch_installed_by_name(argv[i]); + } + + if (pkg == NULL) { + opkg_msg(ERROR, "Package %s is not installed.\n", argv[i]); + continue; + } + if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)|| + ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) { + pkg->state_flag = pkg_state_flag_from_str(flags); + } + + /* + * Useful if a package is installed in an offline_root, and + * should be configured by opkg-cl configure at a later date. + */ + if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){ + pkg->state_status = pkg_state_status_from_str(flags); + } + + opkg_state_changed++; + opkg_msg(NOTICE, "Setting flags for package %s to %s.\n", + pkg->name, flags); + } + + write_status_files_if_changed(); + return 0; +} + +static int +opkg_files_cmd(int argc, char **argv) +{ + pkg_t *pkg; + str_list_t *files; + str_list_elt_t *iter; + char *pkg_version; + + if (argc < 1) { + return -1; + } + + pkg = pkg_hash_fetch_installed_by_name(argv[0]); + if (pkg == NULL) { + opkg_msg(ERROR, "Package %s not installed.\n", argv[0]); + return 0; + } + + files = pkg_get_installed_files(pkg); + pkg_version = pkg_version_str_alloc(pkg); + + printf("Package %s (%s) is installed on %s and has the following files:\n", + pkg->name, pkg_version, pkg->dest->name); + + for (iter=str_list_first(files); iter; iter=str_list_next(files, iter)) + printf("%s\n", (char *)iter->data); + + free(pkg_version); + pkg_free_installed_files(pkg); + + return 0; +} + +static int +opkg_depends_cmd(int argc, char **argv) +{ + int i, j, k; + int depends_count; + pkg_vec_t *available_pkgs; + compound_depend_t *cdep; + pkg_t *pkg; + char *str; + + pkg_info_preinstall_check(); + + available_pkgs = pkg_vec_alloc(); + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + + for (i=0; i<argc; i++) { + for (j=0; j<available_pkgs->len; j++) { + pkg = available_pkgs->pkgs[j]; + + if (fnmatch(argv[i], pkg->name, 0) != 0) + continue; + + depends_count = pkg->depends_count + + pkg->pre_depends_count + + pkg->recommends_count + + pkg->suggests_count; + + opkg_msg(NOTICE, "%s depends on:\n", pkg->name); + + for (k=0; k<depends_count; k++) { + cdep = &pkg->depends[k]; + + if (cdep->type != DEPEND) + continue; + + str = pkg_depend_str(pkg, k); + opkg_msg(NOTICE, "\t%s\n", str); + free(str); + } + + } + } + + pkg_vec_free(available_pkgs); + return 0; +} + +static int +pkg_mark_provides(pkg_t *pkg) +{ + int provides_count = pkg->provides_count; + abstract_pkg_t **provides = pkg->provides; + int i; + pkg->parent->state_flag |= SF_MARKED; + for (i = 0; i < provides_count; i++) { + provides[i]->state_flag |= SF_MARKED; + } + return 0; +} + +enum what_field_type { + WHATDEPENDS, + WHATCONFLICTS, + WHATPROVIDES, + WHATREPLACES, + WHATRECOMMENDS, + WHATSUGGESTS +}; + +static int +opkg_what_depends_conflicts_cmd(enum depend_type what_field_type, int recursive, int argc, char **argv) +{ + depend_t *possibility; + compound_depend_t *cdep; + pkg_vec_t *available_pkgs; + pkg_t *pkg; + int i, j, k, l; + int changed, count; + const char *rel_str = NULL; + char *ver; + + switch (what_field_type) { + case DEPEND: rel_str = "depends on"; break; + case CONFLICTS: rel_str = "conflicts with"; break; + case SUGGEST: rel_str = "suggests"; break; + case RECOMMEND: rel_str = "recommends"; break; + default: return -1; + } + + available_pkgs = pkg_vec_alloc(); + + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + + /* mark the root set */ + pkg_vec_clear_marks(available_pkgs); + opkg_msg(NOTICE, "Root set:\n"); + for (i = 0; i < argc; i++) + pkg_vec_mark_if_matches(available_pkgs, argv[i]); + + for (i = 0; i < available_pkgs->len; i++) { + pkg = available_pkgs->pkgs[i]; + if (pkg->state_flag & SF_MARKED) { + /* mark the parent (abstract) package */ + pkg_mark_provides(pkg); + opkg_msg(NOTICE, " %s\n", pkg->name); + } + } + + opkg_msg(NOTICE, "What %s root set\n", rel_str); + do { + changed = 0; + + for (j=0; j<available_pkgs->len; j++) { + + pkg = available_pkgs->pkgs[j]; + count = ((what_field_type == CONFLICTS) + ? pkg->conflicts_count + : pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count); + + /* skip this package if it is already marked */ + if (pkg->parent->state_flag & SF_MARKED) + continue; + + for (k=0; k<count; k++) { + cdep = (what_field_type == CONFLICTS) + ? &pkg->conflicts[k] + : &pkg->depends[k]; + + if (what_field_type != cdep->type) + continue; + + for (l=0; l<cdep->possibility_count; l++) { + possibility = cdep->possibilities[l]; + + if ((possibility->pkg->state_flag + & SF_MARKED) + != SF_MARKED) + continue; + + /* mark the depending package so we + * won't visit it again */ + pkg->state_flag |= SF_MARKED; + pkg_mark_provides(pkg); + changed++; + + ver = pkg_version_str_alloc(pkg); + opkg_msg(NOTICE, "\t%s %s\t%s %s", + pkg->name, + ver, + rel_str, + possibility->pkg->name); + free(ver); + if (possibility->version) { + opkg_msg(NOTICE, " (%s%s)", + constraint_to_str(possibility->constraint), + possibility->version); + } + if (!pkg_dependence_satisfiable(possibility)) + opkg_msg(NOTICE, + " unsatisfiable"); + opkg_message(NOTICE, "\n"); + goto next_package; + } + } +next_package: + ; + } + } while (changed && recursive); + + pkg_vec_free(available_pkgs); + + return 0; +} + +static int +opkg_whatdepends_recursively_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(DEPEND, 1, argc, argv); +} + +static int +opkg_whatdepends_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(DEPEND, 0, argc, argv); +} + +static int +opkg_whatsuggests_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(SUGGEST, 0, argc, argv); +} + +static int +opkg_whatrecommends_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(RECOMMEND, 0, argc, argv); +} + +static int +opkg_whatconflicts_cmd(int argc, char **argv) +{ + return opkg_what_depends_conflicts_cmd(CONFLICTS, 0, argc, argv); +} + +static int +opkg_what_provides_replaces_cmd(enum what_field_type what_field_type, int argc, char **argv) +{ + + if (argc > 0) { + pkg_vec_t *available_pkgs = pkg_vec_alloc(); + const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces"); + int i; + + pkg_info_preinstall_check(); + + if (conf->query_all) + pkg_hash_fetch_available(available_pkgs); + else + pkg_hash_fetch_all_installed(available_pkgs); + for (i = 0; i < argc; i++) { + const char *target = argv[i]; + int j; + + opkg_msg(NOTICE, "What %s %s\n", + rel_str, target); + for (j = 0; j < available_pkgs->len; j++) { + pkg_t *pkg = available_pkgs->pkgs[j]; + int k; + int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count; + for (k = 0; k < count; k++) { + abstract_pkg_t *apkg = + ((what_field_type == WHATPROVIDES) + ? pkg->provides[k] + : pkg->replaces[k]); + if (fnmatch(target, apkg->name, 0) == 0) { + opkg_msg(NOTICE, " %s", pkg->name); + if (strcmp(target, apkg->name) != 0) + opkg_msg(NOTICE, "\t%s %s\n", + rel_str, apkg->name); + opkg_message(NOTICE, "\n"); + } + } + } + } + pkg_vec_free(available_pkgs); + } + return 0; +} + +static int +opkg_whatprovides_cmd(int argc, char **argv) +{ + return opkg_what_provides_replaces_cmd(WHATPROVIDES, argc, argv); +} + +static int +opkg_whatreplaces_cmd(int argc, char **argv) +{ + return opkg_what_provides_replaces_cmd(WHATREPLACES, argc, argv); +} + +static int +opkg_search_cmd(int argc, char **argv) +{ + int i; + + pkg_vec_t *installed; + pkg_t *pkg; + str_list_t *installed_files; + str_list_elt_t *iter; + char *installed_file; + + if (argc < 1) { + return -1; + } + + installed = pkg_vec_alloc(); + pkg_hash_fetch_all_installed(installed); + pkg_vec_sort(installed, pkg_compare_names); + + for (i=0; i < installed->len; i++) { + pkg = installed->pkgs[i]; + + installed_files = pkg_get_installed_files(pkg); + + for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) { + installed_file = (char *)iter->data; + if (fnmatch(argv[0], installed_file, 0)==0) + print_pkg(pkg); + } + + pkg_free_installed_files(pkg); + } + + pkg_vec_free(installed); + + return 0; +} + +static int +opkg_compare_versions_cmd(int argc, char **argv) +{ + if (argc == 3) { + /* this is a bit gross */ + struct pkg p1, p2; + parse_version(&p1, argv[0]); + parse_version(&p2, argv[2]); + return pkg_version_satisfied(&p1, &p2, argv[1]); + } else { + opkg_msg(ERROR, + "opkg compare_versions <v1> <op> <v2>\n" + "<op> is one of <= >= << >> =\n"); + return -1; + } +} + +static int +opkg_print_architecture_cmd(int argc, char **argv) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l, &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + printf("arch %s %s\n", nv->name, nv->value); + } + return 0; +} + + +/* XXX: CLEANUP: The usage strings should be incorporated into this + array for easier maintenance */ +static opkg_cmd_t cmds[] = { + {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd, PFM_SOURCE}, + {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE}, + {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd, PFM_SOURCE}, + {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE}, + {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd, PFM_SOURCE}, + {"list_changed_conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE}, + {"list-changed-conffiles", 0, (opkg_cmd_fun_t)opkg_list_changed_conffiles_cmd, PFM_SOURCE}, + {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd, 0}, + {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd, PFM_DESCRIPTION|PFM_SOURCE}, + {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd, PFM_DESCRIPTION|PFM_SOURCE}, +}; + +opkg_cmd_t * +opkg_cmd_find(const char *name) +{ + int i; + opkg_cmd_t *cmd; + int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t); + + for (i=0; i < num_cmds; i++) { + cmd = &cmds[i]; + if (strcmp(name, cmd->name) == 0) + return cmd; + } + + return NULL; +} + +int +opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv) +{ + return (cmd->fun)(argc, argv); +} diff --git a/src/libopkg/opkg_cmd.h b/src/libopkg/opkg_cmd.h new file mode 100644 index 0000000..9ca42ff --- /dev/null +++ b/src/libopkg/opkg_cmd.h @@ -0,0 +1,36 @@ +/* opkg_cmd.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_CMD_H +#define OPKG_CMD_H + +typedef int (*opkg_cmd_fun_t)(int argc, const char **argv); + +struct opkg_cmd +{ + const char *name; + int requires_args; + opkg_cmd_fun_t fun; + unsigned int pfm; /* package field mask */ +}; +typedef struct opkg_cmd opkg_cmd_t; + +opkg_cmd_t *opkg_cmd_find(const char *name); +int opkg_cmd_exec(opkg_cmd_t *cmd, int argc, const char **argv); + +extern int opkg_state_changed; +#endif diff --git a/src/libopkg/opkg_conf.c b/src/libopkg/opkg_conf.c new file mode 100644 index 0000000..4711ce7 --- /dev/null +++ b/src/libopkg/opkg_conf.c @@ -0,0 +1,688 @@ +/* opkg_conf.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <glob.h> +#include <unistd.h> + +#include "opkg_conf.h" +#include "pkg_vec.h" +#include "pkg.h" +#include "xregex.h" +#include "sprintf_alloc.h" +#include "opkg_message.h" +#include "file_util.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +static int lock_fd; +static char *lock_file = NULL; + +static opkg_conf_t _conf; +opkg_conf_t *conf = &_conf; + +/* + * Config file options + */ +opkg_option_t options[] = { + { "cache", OPKG_OPT_TYPE_STRING, &_conf.cache}, + { "force_defaults", OPKG_OPT_TYPE_BOOL, &_conf.force_defaults }, + { "force_maintainer", OPKG_OPT_TYPE_BOOL, &_conf.force_maintainer }, + { "force_depends", OPKG_OPT_TYPE_BOOL, &_conf.force_depends }, + { "force_overwrite", OPKG_OPT_TYPE_BOOL, &_conf.force_overwrite }, + { "force_downgrade", OPKG_OPT_TYPE_BOOL, &_conf.force_downgrade }, + { "force_reinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_reinstall }, + { "force_space", OPKG_OPT_TYPE_BOOL, &_conf.force_space }, + { "force_postinstall", OPKG_OPT_TYPE_BOOL, &_conf.force_postinstall }, + { "check_signature", OPKG_OPT_TYPE_BOOL, &_conf.check_signature }, + { "ftp_proxy", OPKG_OPT_TYPE_STRING, &_conf.ftp_proxy }, + { "http_proxy", OPKG_OPT_TYPE_STRING, &_conf.http_proxy }, + { "no_proxy", OPKG_OPT_TYPE_STRING, &_conf.no_proxy }, + { "test", OPKG_OPT_TYPE_BOOL, &_conf.noaction }, + { "noaction", OPKG_OPT_TYPE_BOOL, &_conf.noaction }, + { "download_only", OPKG_OPT_TYPE_BOOL, &_conf.download_only }, + { "nodeps", OPKG_OPT_TYPE_BOOL, &_conf.nodeps }, + { "offline_root", OPKG_OPT_TYPE_STRING, &_conf.offline_root }, + { "overlay_root", OPKG_OPT_TYPE_STRING, &_conf.overlay_root }, + { "proxy_passwd", OPKG_OPT_TYPE_STRING, &_conf.proxy_passwd }, + { "proxy_user", OPKG_OPT_TYPE_STRING, &_conf.proxy_user }, + { "query-all", OPKG_OPT_TYPE_BOOL, &_conf.query_all }, + { "tmp_dir", OPKG_OPT_TYPE_STRING, &_conf.tmp_dir }, + { "verbosity", OPKG_OPT_TYPE_INT, &_conf.verbosity }, +#if defined(HAVE_OPENSSL) + { "signature_ca_file", OPKG_OPT_TYPE_STRING, &_conf.signature_ca_file }, + { "signature_ca_path", OPKG_OPT_TYPE_STRING, &_conf.signature_ca_path }, +#endif +#if defined(HAVE_PATHFINDER) + { "check_x509_path", OPKG_OPT_TYPE_BOOL, &_conf.check_x509_path }, +#endif +#if defined(HAVE_SSLCURL) && defined(HAVE_CURL) + { "ssl_engine", OPKG_OPT_TYPE_STRING, &_conf.ssl_engine }, + { "ssl_cert", OPKG_OPT_TYPE_STRING, &_conf.ssl_cert }, + { "ssl_cert_type", OPKG_OPT_TYPE_STRING, &_conf.ssl_cert_type }, + { "ssl_key", OPKG_OPT_TYPE_STRING, &_conf.ssl_key }, + { "ssl_key_type", OPKG_OPT_TYPE_STRING, &_conf.ssl_key_type }, + { "ssl_key_passwd", OPKG_OPT_TYPE_STRING, &_conf.ssl_key_passwd }, + { "ssl_ca_file", OPKG_OPT_TYPE_STRING, &_conf.ssl_ca_file }, + { "ssl_ca_path", OPKG_OPT_TYPE_STRING, &_conf.ssl_ca_path }, + { "ssl_dont_verify_peer", OPKG_OPT_TYPE_BOOL, &_conf.ssl_dont_verify_peer }, +#endif + { NULL, 0, NULL } +}; + +static int +resolve_pkg_dest_list(void) +{ + nv_pair_list_elt_t *iter; + nv_pair_t *nv_pair; + pkg_dest_t *dest; + char *root_dir; + + for (iter = nv_pair_list_first(&conf->tmp_dest_list); iter; + iter = nv_pair_list_next(&conf->tmp_dest_list, iter)) { + nv_pair = (nv_pair_t *)iter->data; + + if (conf->offline_root) { + sprintf_alloc(&root_dir, "%s%s", conf->offline_root, nv_pair->value); + } else { + root_dir = xstrdup(nv_pair->value); + } + + dest = pkg_dest_list_append(&conf->pkg_dest_list, nv_pair->name, root_dir, conf->lists_dir); + free(root_dir); + + if (conf->default_dest == NULL) + conf->default_dest = dest; + + if (conf->dest_str && !strcmp(dest->name, conf->dest_str)) { + conf->default_dest = dest; + conf->restrict_to_default_dest = 1; + } + } + + if (conf->dest_str && !conf->restrict_to_default_dest) { + opkg_msg(ERROR, "Unknown dest name: `%s'.\n", conf->dest_str); + return -1; + } + + return 0; +} + +static int +opkg_conf_set_option(const char *name, const char *value) +{ + int i = 0; + + while (options[i].name) { + if (strcmp(options[i].name, name) == 0) { + switch (options[i].type) { + case OPKG_OPT_TYPE_BOOL: + if (*(int *)options[i].value) { + opkg_msg(ERROR, "Duplicate boolean option %s, " + "leaving this option on.\n", name); + return 0; + } + *((int * const)options[i].value) = 1; + return 0; + case OPKG_OPT_TYPE_INT: + if (value) { + if (*(int *)options[i].value) { + opkg_msg(ERROR, "Duplicate option %s, " + "using first seen value \"%d\".\n", + name, *((int *)options[i].value)); + return 0; + } + *((int * const)options[i].value) = atoi(value); + return 0; + } else { + opkg_msg(ERROR, "Option %s needs an argument\n", + name); + return -1; + } + case OPKG_OPT_TYPE_STRING: + if (value) { + if (*(char **)options[i].value) { + opkg_msg(ERROR, "Duplicate option %s, " + "using first seen value \"%s\".\n", + name, *((char **)options[i].value)); + return 0; + } + *((char ** const)options[i].value) = xstrdup(value); + return 0; + } else { + opkg_msg(ERROR, "Option %s needs an argument\n", + name); + return -1; + } + } + } + i++; + } + + opkg_msg(ERROR, "Unrecognized option: %s=%s\n", name, value); + return -1; +} + +static int +opkg_conf_parse_file(const char *filename, + pkg_src_list_t *pkg_src_list, + pkg_src_list_t *dist_src_list) +{ + int line_num = 0; + int err = 0; + FILE *file; + regex_t valid_line_re, comment_re; +#define regmatch_size 14 + regmatch_t regmatch[regmatch_size]; + + file = fopen(filename, "r"); + if (file == NULL) { + opkg_perror(ERROR, "Failed to open %s", filename); + err = -1; + goto err0; + } + + opkg_msg(INFO, "Loading conf file %s.\n", filename); + + err = xregcomp(&comment_re, + "^[[:space:]]*(#.*|[[:space:]]*)$", + REG_EXTENDED); + if (err) + goto err1; + + err = xregcomp(&valid_line_re, + "^[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "[[:space:]]*(\"([^\"]*)\"|([^[:space:]]*))" + "([[:space:]]+([^[:space:]]+))?([[:space:]]+(.*))?[[:space:]]*$", + REG_EXTENDED); + if (err) + goto err2; + + while(1) { + char *line; + char *type, *name, *value, *extra; + + line_num++; + + line = file_read_line_alloc(file); + if (line == NULL) + break; + + if (regexec(&comment_re, line, 0, 0, 0) == 0) + goto NEXT_LINE; + + if (regexec(&valid_line_re, line, regmatch_size, regmatch, 0) == REG_NOMATCH) { + opkg_msg(ERROR, "%s:%d: Ignoring invalid line: `%s'\n", + filename, line_num, line); + goto NEXT_LINE; + } + + /* This has to be so ugly to deal with optional quotation marks */ + if (regmatch[2].rm_so > 0) { + type = xstrndup(line + regmatch[2].rm_so, + regmatch[2].rm_eo - regmatch[2].rm_so); + } else { + type = xstrndup(line + regmatch[3].rm_so, + regmatch[3].rm_eo - regmatch[3].rm_so); + } + + if (regmatch[5].rm_so > 0) { + name = xstrndup(line + regmatch[5].rm_so, + regmatch[5].rm_eo - regmatch[5].rm_so); + } else { + name = xstrndup(line + regmatch[6].rm_so, + regmatch[6].rm_eo - regmatch[6].rm_so); + } + + if (regmatch[8].rm_so > 0) { + value = xstrndup(line + regmatch[8].rm_so, + regmatch[8].rm_eo - regmatch[8].rm_so); + } else { + value = xstrndup(line + regmatch[9].rm_so, + regmatch[9].rm_eo - regmatch[9].rm_so); + } + + extra = NULL; + if (regmatch[11].rm_so > 0) { + if (regmatch[13].rm_so > 0 && regmatch[13].rm_so!=regmatch[13].rm_eo ) + extra = xstrndup (line + regmatch[11].rm_so, + regmatch[13].rm_eo - regmatch[11].rm_so); + else + extra = xstrndup (line + regmatch[11].rm_so, + regmatch[11].rm_eo - regmatch[11].rm_so); + } + + if (regmatch[13].rm_so!=regmatch[13].rm_eo && strncmp(type, "dist", 4)!=0) { + opkg_msg(ERROR, "%s:%d: Ignoring config line with trailing garbage: `%s'\n", + filename, line_num, line); + } else { + + /* We use the conf->tmp_dest_list below instead of + conf->pkg_dest_list because we might encounter an + offline_root option later and that would invalidate the + directories we would have computed in + pkg_dest_list_init. (We do a similar thing with + tmp_src_nv_pair_list for sake of symmetry.) */ + if (strcmp(type, "option") == 0) { + opkg_conf_set_option(name, value); + } else if (strcmp(type, "dist") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) dist_src_list, name)) { + pkg_src_list_append (dist_src_list, name, value, extra, 0); + } else { + opkg_msg(ERROR, "Duplicate dist declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "dist/gz") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) dist_src_list, name)) { + pkg_src_list_append (dist_src_list, name, value, extra, 1); + } else { + opkg_msg(ERROR, "Duplicate dist declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "src") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) pkg_src_list, name)) { + pkg_src_list_append (pkg_src_list, name, value, extra, 0); + } else { + opkg_msg(ERROR, "Duplicate src declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "src/gz") == 0) { + if (!nv_pair_list_find((nv_pair_list_t*) pkg_src_list, name)) { + pkg_src_list_append (pkg_src_list, name, value, extra, 1); + } else { + opkg_msg(ERROR, "Duplicate src declaration (%s %s). " + "Skipping.\n", name, value); + } + } else if (strcmp(type, "dest") == 0) { + nv_pair_list_append(&conf->tmp_dest_list, name, value); + } else if (strcmp(type, "lists_dir") == 0) { + conf->lists_dir = xstrdup(value); + } else if (strcmp(type, "arch") == 0) { + opkg_msg(INFO, "Supported arch %s priority (%s)\n", name, value); + if (!value) { + opkg_msg(NOTICE, "No priority given for architecture %s," + "defaulting to 10\n", name); + value = xstrdup("10"); + } + nv_pair_list_append(&conf->arch_list, name, value); + } else { + opkg_msg(ERROR, "%s:%d: Ignoring invalid line: `%s'\n", + filename, line_num, line); + } + + } + + free(type); + free(name); + free(value); + if (extra) + free(extra); + +NEXT_LINE: + free(line); + } + + regfree(&valid_line_re); +err2: + regfree(&comment_re); +err1: + if (fclose(file) == EOF) { + opkg_perror(ERROR, "Couldn't close %s", filename); + err = -1; + } +err0: + return err; +} + +int +opkg_conf_write_status_files(void) +{ + pkg_dest_list_elt_t *iter; + pkg_dest_t *dest; + pkg_vec_t *all; + pkg_t *pkg; + int i, ret = 0; + + if (conf->noaction) + return 0; + + list_for_each_entry(iter, &conf->pkg_dest_list.head, node) { + dest = (pkg_dest_t *)iter->data; + + dest->status_fp = fopen(dest->status_file_name, "w"); + if (dest->status_fp == NULL && errno != EROFS) { + opkg_perror(ERROR, "Can't open status file %s", + dest->status_file_name); + ret = -1; + } + } + + all = pkg_vec_alloc(); + pkg_hash_fetch_available(all); + + for(i = 0; i < all->len; i++) { + pkg = all->pkgs[i]; + /* We don't need most uninstalled packages in the status file */ + if (pkg->state_status == SS_NOT_INSTALLED + && (pkg->state_want == SW_UNKNOWN + || (pkg->state_want == SW_DEINSTALL + && pkg->state_flag != SF_HOLD) + || pkg->state_want == SW_PURGE)) { + continue; + } + if (pkg->dest == NULL) { + opkg_msg(ERROR, "Internal error: package %s has a NULL dest\n", + pkg->name); + continue; + } + if (pkg->dest->status_fp) + pkg_print_status(pkg, pkg->dest->status_fp); + } + + pkg_vec_free(all); + + list_for_each_entry(iter, &conf->pkg_dest_list.head, node) { + dest = (pkg_dest_t *)iter->data; + if (dest->status_fp && fclose(dest->status_fp) == EOF) { + opkg_perror(ERROR, "Couldn't close %s", dest->status_file_name); + ret = -1; + } + } + + return ret; +} + + +char * +root_filename_alloc(char *filename) +{ + char *root_filename; + sprintf_alloc(&root_filename, "%s%s", + (conf->offline_root ? conf->offline_root : ""), filename); + return root_filename; +} + +static int +glob_errfunc(const char *epath, int eerrno) +{ + if (eerrno == ENOENT) + /* If leading dir does not exist, we get GLOB_NOMATCH. */ + return 0; + + opkg_msg(ERROR, "glob failed for %s: %s\n", epath, strerror(eerrno)); + return 0; +} + +int +opkg_conf_init(void) +{ + pkg_src_list_init(&conf->pkg_src_list); + pkg_src_list_init(&conf->dist_src_list); + pkg_dest_list_init(&conf->pkg_dest_list); + pkg_dest_list_init(&conf->tmp_dest_list); + nv_pair_list_init(&conf->arch_list); + + return 0; +} + +int +opkg_conf_load(void) +{ + int i, glob_ret; + char *tmp, *tmp_dir_base, **tmp_val; + glob_t globbuf; + char *etc_opkg_conf_pattern; + + conf->restrict_to_default_dest = 0; + conf->default_dest = NULL; +#if defined(HAVE_PATHFINDER) + conf->check_x509_path = 1; +#endif + + if (!conf->offline_root) + conf->offline_root = xstrdup(getenv("OFFLINE_ROOT")); + + if (conf->conf_file) { + struct stat st; + if (stat(conf->conf_file, &st) == -1) { + opkg_perror(ERROR, "Couldn't stat %s", conf->conf_file); + goto err0; + } + if (opkg_conf_parse_file(conf->conf_file, + &conf->pkg_src_list, &conf->dist_src_list)) + goto err1; + } + + if (conf->offline_root) + sprintf_alloc(&etc_opkg_conf_pattern, "%s/etc/opkg/*.conf", conf->offline_root); + else { + const char *conf_file_dir = getenv("OPKG_CONF_DIR"); + if (conf_file_dir == NULL) + conf_file_dir = OPKG_CONF_DEFAULT_CONF_FILE_DIR; + sprintf_alloc(&etc_opkg_conf_pattern, "%s/*.conf", conf_file_dir); + } + + memset(&globbuf, 0, sizeof(globbuf)); + glob_ret = glob(etc_opkg_conf_pattern, 0, glob_errfunc, &globbuf); + if (glob_ret && glob_ret != GLOB_NOMATCH) { + free(etc_opkg_conf_pattern); + globfree(&globbuf); + goto err1; + } + + free(etc_opkg_conf_pattern); + + for (i = 0; i < globbuf.gl_pathc; i++) { + if (globbuf.gl_pathv[i]) + if (conf->conf_file && + !strcmp(conf->conf_file, globbuf.gl_pathv[i])) + continue; + if ( opkg_conf_parse_file(globbuf.gl_pathv[i], + &conf->pkg_src_list, &conf->dist_src_list)<0) { + globfree(&globbuf); + goto err1; + } + } + + globfree(&globbuf); + + if (conf->offline_root) + sprintf_alloc (&lock_file, "%s/%s", conf->offline_root, OPKGLOCKFILE); + else + sprintf_alloc (&lock_file, "%s", OPKGLOCKFILE); + + lock_fd = creat(lock_file, S_IRUSR | S_IWUSR | S_IRGRP); + if (lock_fd == -1) { + opkg_perror(ERROR, "Could not create lock file %s", lock_file); + goto err2; + } + + if (lockf(lock_fd, F_TLOCK, (off_t)0) == -1) { + opkg_perror(ERROR, "Could not lock %s", lock_file); + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + lock_fd = -1; + goto err2; + } + + if (conf->tmp_dir) + tmp_dir_base = conf->tmp_dir; + else + tmp_dir_base = getenv("TMPDIR"); + + sprintf_alloc(&tmp, "%s/%s", + tmp_dir_base ? tmp_dir_base : OPKG_CONF_DEFAULT_TMP_DIR_BASE, + OPKG_CONF_TMP_DIR_SUFFIX); + if (conf->tmp_dir) + free(conf->tmp_dir); + conf->tmp_dir = mkdtemp(tmp); + if (conf->tmp_dir == NULL) { + opkg_perror(ERROR, "Creating temp dir %s failed", tmp); + goto err3; + } + + pkg_hash_init(); + hash_table_init("file-hash", &conf->file_hash, OPKG_CONF_DEFAULT_HASH_LEN); + hash_table_init("obs-file-hash", &conf->obs_file_hash, OPKG_CONF_DEFAULT_HASH_LEN/16); + + if (conf->lists_dir == NULL) + conf->lists_dir = xstrdup(OPKG_CONF_LISTS_DIR); + + if (conf->offline_root) { + sprintf_alloc(&tmp, "%s/%s", conf->offline_root, conf->lists_dir); + free(conf->lists_dir); + conf->lists_dir = tmp; + } + + /* if no architectures were defined, then default all, noarch, and host architecture */ + if (nv_pair_list_empty(&conf->arch_list)) { + nv_pair_list_append(&conf->arch_list, "all", "1"); + nv_pair_list_append(&conf->arch_list, "noarch", "1"); + nv_pair_list_append(&conf->arch_list, HOST_CPU_STR, "10"); + } + + /* Even if there is no conf file, we'll need at least one dest. */ + if (nv_pair_list_empty(&conf->tmp_dest_list)) { + nv_pair_list_append(&conf->tmp_dest_list, + OPKG_CONF_DEFAULT_DEST_NAME, + OPKG_CONF_DEFAULT_DEST_ROOT_DIR); + } + + if (resolve_pkg_dest_list()) + goto err4; + + nv_pair_list_deinit(&conf->tmp_dest_list); + + return 0; + + +err4: + free(conf->lists_dir); + + pkg_hash_deinit(); + hash_table_deinit(&conf->file_hash); + hash_table_deinit(&conf->obs_file_hash); + + if (rmdir(conf->tmp_dir) == -1) + opkg_perror(ERROR, "Couldn't remove dir %s", conf->tmp_dir); +err3: + if (lockf(lock_fd, F_ULOCK, (off_t)0) == -1) + opkg_perror(ERROR, "Couldn't unlock %s", lock_file); + + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + if (unlink(lock_file) == -1) + opkg_perror(ERROR, "Couldn't unlink %s", lock_file); +err2: + if (lock_file) { + free(lock_file); + lock_file = NULL; + } +err1: + pkg_src_list_deinit(&conf->pkg_src_list); + pkg_src_list_deinit(&conf->dist_src_list); + pkg_dest_list_deinit(&conf->pkg_dest_list); + nv_pair_list_deinit(&conf->arch_list); + + for (i=0; options[i].name; i++) { + if (options[i].type == OPKG_OPT_TYPE_STRING) { + tmp_val = (char **)options[i].value; + if (*tmp_val) { + free(*tmp_val); + *tmp_val = NULL; + } + } + } +err0: + nv_pair_list_deinit(&conf->tmp_dest_list); + if (conf->dest_str) + free(conf->dest_str); + if (conf->conf_file) + free(conf->conf_file); + + return -1; +} + +void +opkg_conf_deinit(void) +{ + int i; + char **tmp; + + if (conf->tmp_dir) + rm_r(conf->tmp_dir); + + if (conf->lists_dir) + free(conf->lists_dir); + + if (conf->dest_str) + free(conf->dest_str); + + if (conf->conf_file) + free(conf->conf_file); + + pkg_src_list_deinit(&conf->pkg_src_list); + pkg_src_list_deinit(&conf->dist_src_list); + pkg_dest_list_deinit(&conf->pkg_dest_list); + nv_pair_list_deinit(&conf->arch_list); + + for (i=0; options[i].name; i++) { + if (options[i].type == OPKG_OPT_TYPE_STRING) { + tmp = (char **)options[i].value; + if (*tmp) { + free(*tmp); + *tmp = NULL; + } + } + } + + if (conf->verbosity >= DEBUG) { + hash_print_stats(&conf->pkg_hash); + hash_print_stats(&conf->file_hash); + hash_print_stats(&conf->obs_file_hash); + } + + pkg_hash_deinit(); + hash_table_deinit(&conf->file_hash); + hash_table_deinit(&conf->obs_file_hash); + + if (lock_fd != -1) { + if (lockf(lock_fd, F_ULOCK, (off_t)0) == -1) + opkg_perror(ERROR, "Couldn't unlock %s", lock_file); + + if (close(lock_fd) == -1) + opkg_perror(ERROR, "Couldn't close descriptor %d (%s)", + lock_fd, lock_file); + + } + + if (lock_file) { + if (unlink(lock_file) == -1) + opkg_perror(ERROR, "Couldn't unlink %s", lock_file); + + free(lock_file); + } +} diff --git a/src/libopkg/opkg_conf.h b/src/libopkg/opkg_conf.h new file mode 100644 index 0000000..3a60bc5 --- /dev/null +++ b/src/libopkg/opkg_conf.h @@ -0,0 +1,145 @@ +/* opkg_conf.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_CONF_H +#define OPKG_CONF_H + +typedef struct opkg_conf opkg_conf_t; +extern opkg_conf_t *conf; + +#include "config.h" + +#include <stdarg.h> + +#include "hash_table.h" +#include "pkg_src_list.h" +#include "pkg_dest_list.h" +#include "nv_pair_list.h" + +#define OPKG_CONF_DEFAULT_TMP_DIR_BASE "/tmp" +#define OPKG_CONF_TMP_DIR_SUFFIX "opkg-XXXXXX" +#define OPKG_CONF_LISTS_DIR OPKG_STATE_DIR_PREFIX "/lists" + +#define OPKG_CONF_DEFAULT_CONF_FILE_DIR OPKGETCDIR"/opkg" + +/* In case the config file defines no dest */ +#define OPKG_CONF_DEFAULT_DEST_NAME "root" +#define OPKG_CONF_DEFAULT_DEST_ROOT_DIR "/" + +#define OPKG_CONF_DEFAULT_HASH_LEN 1024 + +struct opkg_conf +{ + pkg_src_list_t pkg_src_list; + pkg_src_list_t dist_src_list; + pkg_dest_list_t pkg_dest_list; + pkg_dest_list_t tmp_dest_list; + nv_pair_list_t arch_list; + + int restrict_to_default_dest; + pkg_dest_t *default_dest; + char *dest_str; + + char *conf_file; + + char *tmp_dir; + char *lists_dir; + + unsigned int pfm; /* package field mask */ + + /* For libopkg users to capture messages. */ + void (*opkg_vmessage)(int, const char *fmt, va_list ap); + + /* options */ + int autoremove; + int force_depends; + int force_defaults; + int force_maintainer; + int force_overwrite; + int force_downgrade; + int force_reinstall; + int force_space; + int force_removal_of_dependent_packages; + int force_removal_of_essential_packages; + int force_postinstall; + int force_remove; + int check_signature; + int nodeps; /* do not follow dependencies */ + char *offline_root; + char *overlay_root; + int query_all; + int verbosity; + int noaction; + int download_only; + char *cache; + +#ifdef HAVE_SSLCURL + /* some options could be used by + * wget if curl support isn't builtin + * If someone want to try... + */ + char *ssl_engine; + char *ssl_cert; + char *ssl_cert_type; + char *ssl_key; + char *ssl_key_type; + char *ssl_key_passwd; + char *ssl_ca_file; + char *ssl_ca_path; + int ssl_dont_verify_peer; +#endif +#ifdef HAVE_PATHFINDER + int check_x509_path; +#endif + + /* proxy options */ + char *http_proxy; + char *ftp_proxy; + char *no_proxy; + char *proxy_user; + char *proxy_passwd; + + char *signature_ca_file; + char *signature_ca_path; + + hash_table_t pkg_hash; + hash_table_t file_hash; + hash_table_t obs_file_hash; +}; + +enum opkg_option_type { + OPKG_OPT_TYPE_BOOL, + OPKG_OPT_TYPE_INT, + OPKG_OPT_TYPE_STRING +}; +typedef enum opkg_option_type opkg_option_type_t; + +typedef struct opkg_option opkg_option_t; +struct opkg_option { + const char *name; + const opkg_option_type_t type; + void * const value; +}; + +int opkg_conf_init(void); +int opkg_conf_load(void); +void opkg_conf_deinit(void); + +int opkg_conf_write_status_files(void); +char *root_filename_alloc(char *filename); + +#endif diff --git a/src/libopkg/opkg_configure.c b/src/libopkg/opkg_configure.c new file mode 100644 index 0000000..719da5a --- /dev/null +++ b/src/libopkg/opkg_configure.c @@ -0,0 +1,44 @@ +/* opkg_configure.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> + +#include "sprintf_alloc.h" +#include "opkg_configure.h" +#include "opkg_message.h" +#include "opkg_cmd.h" + +int +opkg_configure(pkg_t *pkg) +{ + int err; + + /* DPKG_INCOMPATIBILITY: + dpkg actually does some conffile handling here, rather than at the + end of opkg_install(). Do we care? */ + /* DPKG_INCOMPATIBILITY: + dpkg actually includes a version number to this script call */ + + err = pkg_run_script(pkg, "postinst", "configure"); + if (err) { + opkg_msg(ERROR, "%s.postinst returned %d.\n", pkg->name, err); + return err; + } + + return 0; +} + diff --git a/src/libopkg/opkg_configure.h b/src/libopkg/opkg_configure.h new file mode 100644 index 0000000..ff01ff3 --- /dev/null +++ b/src/libopkg/opkg_configure.h @@ -0,0 +1,25 @@ +/* opkg_configure.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_CONFIGURE_H +#define OPKG_CONFIGURE_H + +#include "pkg.h" + +int opkg_configure(pkg_t *pkg); + +#endif diff --git a/src/libopkg/opkg_defines.h b/src/libopkg/opkg_defines.h new file mode 100644 index 0000000..090d7d4 --- /dev/null +++ b/src/libopkg/opkg_defines.h @@ -0,0 +1,35 @@ +/* opkg_defines.h - the opkg package management system + + Copyright (C) 2008 OpenMoko 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, 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. +*/ + +#ifndef OPKG_DEFINES_H +#define OPKG_DEFINES_H + +#define OPKG_PKG_EXTENSION ".opk" +#define IPKG_PKG_EXTENSION ".ipk" +#define DPKG_PKG_EXTENSION ".deb" + +#define OPKG_LEGAL_PKG_NAME_CHARS "abcdefghijklmnopqrstuvwxyz0123456789.+-" +#define OPKG_PKG_VERSION_SEP_CHAR '_' + +#define OPKG_STATE_DIR_PREFIX OPKGLIBDIR"/opkg" +#define OPKG_LISTS_DIR_SUFFIX "lists" +#define OPKG_INFO_DIR_SUFFIX "info" +#define OPKG_STATUS_FILE_SUFFIX "status" + +#define OPKG_BACKUP_SUFFIX "-opkg.backup" + +#define OPKG_LIST_DESCRIPTION_LENGTH 128 + +#endif /* OPKG_DEFINES_H */ diff --git a/src/libopkg/opkg_download.c b/src/libopkg/opkg_download.c new file mode 100644 index 0000000..e53e64e --- /dev/null +++ b/src/libopkg/opkg_download.c @@ -0,0 +1,679 @@ +/* vi: set noexpandtab sw=4 sts=4: */ +/* opkg_download.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + Copyright (C) 2008 OpenMoko 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <libgen.h> + +#include "opkg_download.h" +#include "opkg_message.h" + +#include "sprintf_alloc.h" +#include "xsystem.h" +#include "file_util.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +#ifdef HAVE_CURL +#include <curl/curl.h> +#endif + +#if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL) +#include <openssl/conf.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/ssl.h> +#endif + +#if defined(HAVE_GPGME) +#include <gpgme.h> +#elif defined(HAVE_OPENSSL) +#include <openssl/bio.h> +#include <openssl/objects.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/hmac.h> +#endif + +#ifdef HAVE_PATHFINDER +#include "opkg_pathfinder.h" +#endif + +#if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL) +static void openssl_init(void); +#endif + +#ifdef HAVE_OPENSSL +static X509_STORE *setup_verify(char *CAfile, char *CApath); +#endif + +#ifdef HAVE_CURL +/* + * Make curl an instance variable so we don't have to instanciate it + * each time + */ +static CURL *curl = NULL; +static CURL *opkg_curl_init(curl_progress_func cb, void *data); +#endif + +static int +str_starts_with(const char *str, const char *prefix) +{ + return (strncmp(str, prefix, strlen(prefix)) == 0); +} + +int +opkg_download(const char *src, const char *dest_file_name, + curl_progress_func cb, void *data, const short hide_error) +{ + int err = 0; + + char *src_basec = xstrdup(src); + char *src_base = basename(src_basec); + char *tmp_file_location; + + opkg_msg(NOTICE,"Downloading %s.\n", src); + + if (str_starts_with(src, "file:")) { + const char *file_src = src + 5; + opkg_msg(INFO, "Copying %s to %s...", file_src, dest_file_name); + err = file_copy(file_src, dest_file_name); + opkg_msg(INFO, "Done.\n"); + free(src_basec); + return err; + } + + sprintf_alloc(&tmp_file_location, "%s/%s", conf->tmp_dir, src_base); + free(src_basec); + err = unlink(tmp_file_location); + if (err && errno != ENOENT) { + opkg_perror(ERROR, "Failed to unlink %s", tmp_file_location); + free(tmp_file_location); + return -1; + } + + if (conf->http_proxy) { + opkg_msg(DEBUG, "Setting environment variable: http_proxy = %s.\n", + conf->http_proxy); + setenv("http_proxy", conf->http_proxy, 1); + } + if (conf->ftp_proxy) { + opkg_msg(DEBUG, "Setting environment variable: ftp_proxy = %s.\n", + conf->ftp_proxy); + setenv("ftp_proxy", conf->ftp_proxy, 1); + } + if (conf->no_proxy) { + opkg_msg(DEBUG,"Setting environment variable: no_proxy = %s.\n", + conf->no_proxy); + setenv("no_proxy", conf->no_proxy, 1); + } + +#ifdef HAVE_CURL + CURLcode res; + FILE * file = fopen (tmp_file_location, "w"); + + curl = opkg_curl_init (cb, data); + if (curl) + { + curl_easy_setopt (curl, CURLOPT_URL, src); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, file); + + res = curl_easy_perform (curl); + fclose (file); + if (res) + { + long error_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &error_code); + opkg_msg(hide_error?DEBUG2:ERROR, "Failed to download %s: %s.\n", + src, curl_easy_strerror(res)); + free(tmp_file_location); + return -1; + } + + } + else + { + free(tmp_file_location); + return -1; + } +#else + { + int res; + const char *argv[8]; + int i = 0; + + argv[i++] = "wget"; + argv[i++] = "-q"; + if (conf->http_proxy || conf->ftp_proxy) { + argv[i++] = "-Y"; + argv[i++] = "on"; + } + argv[i++] = "-O"; + argv[i++] = tmp_file_location; + argv[i++] = src; + argv[i++] = NULL; + res = xsystem(argv); + + if (res) { + opkg_msg(ERROR, "Failed to download %s, wget returned %d.\n", src, res); + free(tmp_file_location); + return -1; + } + } +#endif + + err = file_move(tmp_file_location, dest_file_name); + + free(tmp_file_location); + + return err; +} + +static int +opkg_download_cache(const char *src, const char *dest_file_name, + curl_progress_func cb, void *data) +{ + char *cache_name = xstrdup(src); + char *cache_location, *p; + int err = 0; + + if (!conf->cache || str_starts_with(src, "file:")) { + err = opkg_download(src, dest_file_name, cb, data, 0); + goto out1; + } + + if(!file_is_dir(conf->cache)){ + opkg_msg(ERROR, "%s is not a directory.\n", + conf->cache); + err = 1; + goto out1; + } + + for (p = cache_name; *p; p++) + if (*p == '/') + *p = ','; /* looks nicer than | or # */ + + sprintf_alloc(&cache_location, "%s/%s", conf->cache, cache_name); + if (file_exists(cache_location)) + opkg_msg(NOTICE, "Copying %s.\n", cache_location); + else { + /* cache file with funky name not found, try simple name */ + free(cache_name); + char *filename = strrchr(dest_file_name,'/'); + if (filename) + cache_name = xstrdup(filename+1); // strip leading '/' + else + cache_name = xstrdup(dest_file_name); + free(cache_location); + sprintf_alloc(&cache_location, "%s/%s", conf->cache, cache_name); + if (file_exists(cache_location)) + opkg_msg(NOTICE, "Copying %s.\n", cache_location); + else { + err = opkg_download(src, cache_location, cb, data, 0); + if (err) { + (void) unlink(cache_location); + goto out2; + } + } + } + + err = file_copy(cache_location, dest_file_name); + + +out2: + free(cache_location); +out1: + free(cache_name); + return err; +} + +int +opkg_download_pkg(pkg_t *pkg, const char *dir) +{ + int err; + char *url; + char *stripped_filename; + + if (pkg->src == NULL) { + opkg_msg(ERROR, "Package %s is not available from any configured src.\n", + pkg->name); + return -1; + } + if (pkg->filename == NULL) { + opkg_msg(ERROR, "Package %s does not have a valid filename field.\n", + pkg->name); + return -1; + } + + sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename); + + /* The pkg->filename might be something like + "../../foo.opk". While this is correct, and exactly what we + want to use to construct url above, here we actually need to + use just the filename part, without any directory. */ + + stripped_filename = strrchr(pkg->filename, '/'); + if ( ! stripped_filename ) + stripped_filename = pkg->filename; + + sprintf_alloc(&pkg->local_filename, "%s/%s", dir, stripped_filename); + + err = opkg_download_cache(url, pkg->local_filename, NULL, NULL); + free(url); + + return err; +} + +/* + * Downloads file from url, installs in package database, return package name. + */ +int +opkg_prepare_url_for_install(const char *url, char **namep) +{ + int err = 0; + pkg_t *pkg; + + pkg = pkg_new(); + + if (str_starts_with(url, "http://") + || str_starts_with(url, "ftp://")) { + char *tmp_file; + char *file_basec = xstrdup(url); + char *file_base = basename(file_basec); + + sprintf_alloc(&tmp_file, "%s/%s", conf->tmp_dir, file_base); + err = opkg_download(url, tmp_file, NULL, NULL, 0); + if (err) + return err; + + err = pkg_init_from_file(pkg, tmp_file); + if (err) + return err; + + free(tmp_file); + free(file_basec); + + } else if (strcmp(&url[strlen(url) - 4], OPKG_PKG_EXTENSION) == 0 + || strcmp(&url[strlen(url) - 4], IPKG_PKG_EXTENSION) == 0 + || strcmp(&url[strlen(url) - 4], DPKG_PKG_EXTENSION) == 0) { + + err = pkg_init_from_file(pkg, url); + if (err) + return err; + opkg_msg(DEBUG2, "Package %s provided by hand (%s).\n", + pkg->name, pkg->local_filename); + pkg->provided_by_hand = 1; + + } else { + pkg_deinit(pkg); + free(pkg); + return 0; + } + + pkg->dest = conf->default_dest; + pkg->state_want = SW_INSTALL; + pkg->state_flag |= SF_PREFER; + hash_insert_pkg(pkg, 1); + + if (namep) { + *namep = pkg->name; + } + return 0; +} + +int +opkg_verify_file (char *text_file, char *sig_file) +{ +#if defined HAVE_GPGME + if (conf->check_signature == 0 ) + return 0; + int status = -1; + gpgme_ctx_t ctx; + gpgme_data_t sig, text, key; + gpgme_error_t err; + gpgme_verify_result_t result; + gpgme_signature_t s; + char *trusted_path = NULL; + + gpgme_check_version (NULL); + + err = gpgme_new (&ctx); + + if (err) + return -1; + + trusted_path = root_filename_alloc("/etc/opkg/trusted.gpg"); + err = gpgme_data_new_from_file (&key, trusted_path, 1); + free (trusted_path); + if (err) + { + return -1; + } + err = gpgme_op_import (ctx, key); + if (err) + { + gpgme_data_release (key); + return -1; + } + gpgme_data_release (key); + + err = gpgme_data_new_from_file (&sig, sig_file, 1); + if (err) + { + gpgme_release (ctx); + return -1; + } + + err = gpgme_data_new_from_file (&text, text_file, 1); + if (err) + { + gpgme_data_release (sig); + gpgme_release (ctx); + return -1; + } + + err = gpgme_op_verify (ctx, sig, text, NULL); + + result = gpgme_op_verify_result (ctx); + if (!result) + return -1; + + /* see if any of the signitures matched */ + s = result->signatures; + while (s) + { + status = gpg_err_code (s->status); + if (status == GPG_ERR_NO_ERROR) + break; + s = s->next; + } + + + gpgme_data_release (sig); + gpgme_data_release (text); + gpgme_release (ctx); + + return status; +#elif defined HAVE_OPENSSL + X509_STORE *store = NULL; + PKCS7 *p7 = NULL; + BIO *in = NULL, *indata = NULL; + + // Sig check failed by default ! + int status = -1; + + openssl_init(); + + // Set-up the key store + if(!(store = setup_verify(conf->signature_ca_file, conf->signature_ca_path))){ + opkg_msg(ERROR, "Can't open CA certificates.\n"); + goto verify_file_end; + } + + // Open a BIO to read the sig file + if (!(in = BIO_new_file(sig_file, "rb"))){ + opkg_msg(ERROR, "Can't open signature file %s.\n", sig_file); + goto verify_file_end; + } + + // Read the PKCS7 block contained in the sig file + p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); + if(!p7){ + opkg_msg(ERROR, "Can't read signature file %s (Corrupted ?).\n", + sig_file); + goto verify_file_end; + } +#if defined(HAVE_PATHFINDER) + if(conf->check_x509_path){ + if(!pkcs7_pathfinder_verify_signers(p7)){ + opkg_msg(ERROR, "pkcs7_pathfinder_verify_signers: " + "Path verification failed.\n"); + goto verify_file_end; + } + } +#endif + + // Open the Package file to authenticate + if (!(indata = BIO_new_file(text_file, "rb"))){ + opkg_msg(ERROR, "Can't open file %s.\n", text_file); + goto verify_file_end; + } + + // Let's verify the autenticity ! + if (PKCS7_verify(p7, NULL, store, indata, NULL, PKCS7_BINARY) != 1){ + // Get Off My Lawn! + opkg_msg(ERROR, "Verification failure.\n"); + }else{ + // Victory ! + status = 0; + } + +verify_file_end: + BIO_free(in); + BIO_free(indata); + PKCS7_free(p7); + X509_STORE_free(store); + + return status; +#else + /* mute `unused variable' warnings. */ + (void) sig_file; + (void) text_file; + (void) conf; + return 0; +#endif +} + + +#if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL) +static void openssl_init(void){ + static int init = 0; + + if(!init){ + OPENSSL_config(NULL); + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + init = 1; + } +} + +#endif + + +#if defined HAVE_OPENSSL +static X509_STORE * +setup_verify(char *CAfile, char *CApath) +{ + X509_STORE *store = NULL; + X509_LOOKUP *lookup = NULL; + + if(!(store = X509_STORE_new())){ + // Something bad is happening... + goto end; + } + + // adds the X509 file lookup method + lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file()); + if (lookup == NULL){ + goto end; + } + + // Autenticating against one CA file + if (CAfile) { + if(!X509_LOOKUP_load_file(lookup,CAfile,X509_FILETYPE_PEM)) { + // Invalid CA => Bye bye + opkg_msg(ERROR, "Error loading file %s.\n", CAfile); + goto end; + } + } else { + X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT); + } + + // Now look into CApath directory if supplied + lookup = X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir()); + if (lookup == NULL){ + goto end; + } + + if (CApath) { + if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) { + opkg_msg(ERROR, "Error loading directory %s.\n", CApath); + goto end; + } + } else { + X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT); + } + + // All right ! + ERR_clear_error(); + return store; + +end: + + X509_STORE_free(store); + return NULL; + +} + +#endif + +#ifdef HAVE_CURL +void opkg_curl_cleanup(void){ + if(curl != NULL){ + curl_easy_cleanup (curl); + curl = NULL; + } +} + +static CURL * +opkg_curl_init(curl_progress_func cb, void *data) +{ + + if(curl == NULL){ + curl = curl_easy_init(); + +#ifdef HAVE_SSLCURL + openssl_init(); + + if (conf->ssl_engine) { + + /* use crypto engine */ + if (curl_easy_setopt(curl, CURLOPT_SSLENGINE, conf->ssl_engine) != CURLE_OK){ + opkg_msg(ERROR, "Can't set crypto engine '%s'.\n", + conf->ssl_engine); + + opkg_curl_cleanup(); + return NULL; + } + /* set the crypto engine as default */ + if (curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L) != CURLE_OK){ + opkg_msg(ERROR, "Can't set crypto engine '%s' as default.\n", + conf->ssl_engine); + + opkg_curl_cleanup(); + return NULL; + } + } + + /* cert & key can only be in PEM case in the same file */ + if(conf->ssl_key_passwd){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, conf->ssl_key_passwd) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key password.\n"); + } + } + + /* sets the client certificate and its type */ + if(conf->ssl_cert_type){ + if (curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, conf->ssl_cert_type) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set certificate format.\n"); + } + } + /* SSL cert name isn't mandatory */ + if(conf->ssl_cert){ + curl_easy_setopt(curl, CURLOPT_SSLCERT, conf->ssl_cert); + } + + /* sets the client key and its type */ + if(conf->ssl_key_type){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, conf->ssl_key_type) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key format.\n"); + } + } + if(conf->ssl_key){ + if (curl_easy_setopt(curl, CURLOPT_SSLKEY, conf->ssl_key) != CURLE_OK) + { + opkg_msg(DEBUG, "Failed to set key.\n"); + } + } + + /* Should we verify the peer certificate ? */ + if(conf->ssl_dont_verify_peer){ + /* + * CURLOPT_SSL_VERIFYPEER default is nonzero (curl => 7.10) + */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + }else{ +#ifdef HAVE_PATHFINDER + if(conf->check_x509_path){ + if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_ssl_ctx_function) != CURLE_OK){ + opkg_msg(DEBUG, "Failed to set ssl path verification callback.\n"); + }else{ + curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, NULL); + } + } +#endif + } + + /* certification authority file and/or path */ + if(conf->ssl_ca_file){ + curl_easy_setopt(curl, CURLOPT_CAINFO, conf->ssl_ca_file); + } + if(conf->ssl_ca_path){ + curl_easy_setopt(curl, CURLOPT_CAPATH, conf->ssl_ca_path); + } +#endif + + curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1); + if (conf->http_proxy || conf->ftp_proxy) + { + char *userpwd; + sprintf_alloc (&userpwd, "%s:%s", conf->proxy_user, + conf->proxy_passwd); + curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, userpwd); + free (userpwd); + } + } + + curl_easy_setopt (curl, CURLOPT_NOPROGRESS, (cb == NULL)); + if (cb) + { + curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, data); + curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, cb); + } + + return curl; + +} +#endif diff --git a/src/libopkg/opkg_download.h b/src/libopkg/opkg_download.h new file mode 100644 index 0000000..91b990e --- /dev/null +++ b/src/libopkg/opkg_download.h @@ -0,0 +1,39 @@ +/* opkg_download.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_DOWNLOAD_H +#define OPKG_DOWNLOAD_H + +#include "config.h" +#include "pkg.h" + +typedef void (*opkg_download_progress_callback)(int percent, char *url); +typedef int (*curl_progress_func)(void *data, double t, double d, double ultotal, double ulnow); + + +int opkg_download(const char *src, const char *dest_file_name, curl_progress_func cb, void *data, const short hide_error); +int opkg_download_pkg(pkg_t *pkg, const char *dir); +/* + * Downloads file from url, installs in package database, return package name. + */ +int opkg_prepare_url_for_install(const char *url, char **namep); + +int opkg_verify_file (char *text_file, char *sig_file); +#ifdef HAVE_CURL +void opkg_curl_cleanup(void); +#endif +#endif diff --git a/src/libopkg/opkg_install.c b/src/libopkg/opkg_install.c new file mode 100644 index 0000000..3925f58 --- /dev/null +++ b/src/libopkg/opkg_install.c @@ -0,0 +1,1528 @@ +/* opkg_install.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <unistd.h> +#include <sys/stat.h> + +#include "pkg.h" +#include "pkg_hash.h" +#include "pkg_extract.h" + +#include "opkg_install.h" +#include "opkg_configure.h" +#include "opkg_download.h" +#include "opkg_remove.h" + +#include "opkg_utils.h" +#include "opkg_message.h" +#include "opkg_cmd.h" +#include "opkg_defines.h" + +#include "sprintf_alloc.h" +#include "file_util.h" +#include "xsystem.h" +#include "libbb/libbb.h" + +static int +satisfy_dependencies_for(pkg_t *pkg) +{ + int i, err; + pkg_vec_t *depends = pkg_vec_alloc(); + pkg_t *dep; + char **tmp, **unresolved = NULL; + int ndepends; + + ndepends = pkg_hash_fetch_unsatisfied_dependencies(pkg, depends, + &unresolved); + + if (unresolved) { + opkg_msg(ERROR, "Cannot satisfy the following dependencies for %s:\n", + pkg->name); + tmp = unresolved; + while (*unresolved) { + opkg_message(ERROR, "\t%s", *unresolved); + free(*unresolved); + unresolved++; + } + free(tmp); + opkg_message(ERROR, "\n"); + if (! conf->force_depends) { + opkg_msg(INFO, + "This could mean that your package list is out of date or that the packages\n" + "mentioned above do not yet exist (try 'opkg update'). To proceed in spite\n" + "of this problem try again with the '-force-depends' option.\n"); + pkg_vec_free(depends); + return -1; + } + } + + if (ndepends <= 0) { + pkg_vec_free(depends); + return 0; + } + + /* Mark packages as to-be-installed */ + for (i=0; i < depends->len; i++) { + /* Dependencies should be installed the same place as pkg */ + if (depends->pkgs[i]->dest == NULL) { + depends->pkgs[i]->dest = pkg->dest; + } + depends->pkgs[i]->state_want = SW_INSTALL; + } + + for (i = 0; i < depends->len; i++) { + dep = depends->pkgs[i]; + /* The package was uninstalled when we started, but another + dep earlier in this loop may have depended on it and pulled + it in, so check first. */ + if ((dep->state_status != SS_INSTALLED) + && (dep->state_status != SS_UNPACKED)) { + opkg_msg(DEBUG2,"Calling opkg_install_pkg.\n"); + err = opkg_install_pkg(dep, 0); + /* mark this package as having been automatically installed to + * satisfy a dependancy */ + dep->auto_installed = 1; + if (err) { + pkg_vec_free(depends); + return err; + } + } + } + + pkg_vec_free(depends); + + return 0; +} + +static int +check_conflicts_for(pkg_t *pkg) +{ + int i; + pkg_vec_t *conflicts = NULL; + message_level_t level; + + if (conf->force_depends) { + level = NOTICE; + } else { + level = ERROR; + } + + if (!conf->force_depends) + conflicts = pkg_hash_fetch_conflicts(pkg); + + if (conflicts) { + opkg_msg(level, "The following packages conflict with %s:\n", + pkg->name); + i = 0; + while (i < conflicts->len) + opkg_msg(level, "\t%s", conflicts->pkgs[i++]->name); + opkg_message(level, "\n"); + pkg_vec_free(conflicts); + return -1; + } + return 0; +} + +static int +update_file_ownership(pkg_t *new_pkg, pkg_t *old_pkg) +{ + str_list_t *new_list, *old_list; + str_list_elt_t *iter, *niter; + + new_list = pkg_get_installed_files(new_pkg); + if (new_list == NULL) + return -1; + + for (iter = str_list_first(new_list), niter = str_list_next(new_list, iter); + iter; + iter = niter, niter = str_list_next(new_list, niter)) { + char *new_file = (char *)iter->data; + pkg_t *owner = file_hash_get_file_owner(new_file); + pkg_t *obs = hash_table_get(&conf->obs_file_hash, new_file); + + opkg_msg(DEBUG2, "%s: new_pkg=%s wants file %s, from owner=%s\n", + __func__, new_pkg->name, new_file, owner?owner->name:"<NULL>"); + + if (!owner || (owner == old_pkg) || obs) + file_hash_set_file_owner(new_file, new_pkg); + } + + if (old_pkg) { + old_list = pkg_get_installed_files(old_pkg); + if (old_list == NULL) { + pkg_free_installed_files(new_pkg); + return -1; + } + + for (iter = str_list_first(old_list), niter = str_list_next(old_list, iter); + iter; + iter = niter, niter = str_list_next(old_list, niter)) { + char *old_file = (char *)iter->data; + pkg_t *owner = file_hash_get_file_owner(old_file); + if (!owner || (owner == old_pkg)) { + /* obsolete */ + hash_table_insert(&conf->obs_file_hash, old_file, old_pkg); + } + } + pkg_free_installed_files(old_pkg); + } + pkg_free_installed_files(new_pkg); + return 0; +} + +static int +verify_pkg_installable(pkg_t *pkg) +{ + unsigned long kbs_available, pkg_size_kbs; + char *root_dir = NULL; + struct stat s; + + if (conf->force_space || pkg->installed_size == 0) + return 0; + + if (pkg->dest) + { + if (!strcmp(pkg->dest->name, "root") && conf->overlay_root + && !stat(conf->overlay_root, &s) && (s.st_mode & S_IFDIR)) + root_dir = conf->overlay_root; + else + root_dir = pkg->dest->root_dir; + } + + if (!root_dir) + root_dir = conf->default_dest->root_dir; + + kbs_available = get_available_kbytes(root_dir); + + pkg_size_kbs = (pkg->installed_size + 1023)/1024; + + if (pkg_size_kbs >= kbs_available) { + opkg_msg(ERROR, "Only have %ldkb available on filesystem %s, " + "pkg %s needs %ld\n", + kbs_available, root_dir, pkg->name, pkg_size_kbs); + return -1; + } + + return 0; +} + +static int +unpack_pkg_control_files(pkg_t *pkg) +{ + int err; + char *conffiles_file_name; + char *root_dir; + FILE *conffiles_file; + + sprintf_alloc(&pkg->tmp_unpack_dir, "%s/%s-XXXXXX", conf->tmp_dir, pkg->name); + + pkg->tmp_unpack_dir = mkdtemp(pkg->tmp_unpack_dir); + if (pkg->tmp_unpack_dir == NULL) { + opkg_perror(ERROR, "Failed to create temporary directory '%s'", + pkg->tmp_unpack_dir); + return -1; + } + + err = pkg_extract_control_files_to_dir(pkg, pkg->tmp_unpack_dir); + if (err) { + return err; + } + + /* XXX: CLEANUP: There might be a cleaner place to read in the + conffiles. Seems like I should be able to get everything to go + through pkg_init_from_file. If so, maybe it would make sense to + move all of unpack_pkg_control_files to that function. */ + + /* Don't need to re-read conffiles if we already have it */ + if (!nv_pair_list_empty(&pkg->conffiles)) { + return 0; + } + + sprintf_alloc(&conffiles_file_name, "%s/conffiles", pkg->tmp_unpack_dir); + if (! file_exists(conffiles_file_name)) { + free(conffiles_file_name); + return 0; + } + + conffiles_file = fopen(conffiles_file_name, "r"); + if (conffiles_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", conffiles_file_name); + free(conffiles_file_name); + return -1; + } + free(conffiles_file_name); + + while (1) { + char *cf_name; + char *cf_name_in_dest; + + cf_name = file_read_line_alloc(conffiles_file); + if (cf_name == NULL) { + break; + } + if (cf_name[0] == '\0') { + continue; + } + + /* Prepend dest->root_dir to conffile name. + Take pains to avoid multiple slashes. */ + root_dir = pkg->dest->root_dir; + if (conf->offline_root) + /* skip the offline_root prefix */ + root_dir = pkg->dest->root_dir + strlen(conf->offline_root); + sprintf_alloc(&cf_name_in_dest, "%s%s", root_dir, + cf_name[0] == '/' ? (cf_name + 1) : cf_name); + + /* Can't get an md5sum now, (file isn't extracted yet). + We'll wait until resolve_conffiles */ + conffile_list_append(&pkg->conffiles, cf_name_in_dest, NULL); + + free(cf_name); + free(cf_name_in_dest); + } + + fclose(conffiles_file); + + return 0; +} + +/* + * Remove packages which were auto_installed due to a dependency by old_pkg, + * which are no longer a dependency in the new (upgraded) pkg. + */ +static int +pkg_remove_orphan_dependent(pkg_t *pkg, pkg_t *old_pkg) +{ + int i, j, k, l, found,r, err = 0; + int n_deps; + pkg_t *p; + struct compound_depend *cd0, *cd1; + abstract_pkg_t **dependents; + + int count0 = old_pkg->pre_depends_count + + old_pkg->depends_count + + old_pkg->recommends_count + + old_pkg->suggests_count; + int count1 = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count0; i++) { + cd0 = &old_pkg->depends[i]; + if (cd0->type != DEPEND) + continue; + for (j=0; j<cd0->possibility_count; j++) { + + found = 0; + + for (k=0; k<count1; k++) { + cd1 = &pkg->depends[k]; + if (cd1->type != DEPEND) + continue; + for (l=0; l<cd1->possibility_count; l++) { + if (cd0->possibilities[j] + == cd1->possibilities[l]) { + found = 1; + break; + } + } + if (found) + break; + } + + if (found) + continue; + + /* + * old_pkg has a dependency that pkg does not. + */ + p = pkg_hash_fetch_installed_by_name( + cd0->possibilities[j]->pkg->name); + + if (!p) + continue; + + if (!p->auto_installed) + continue; + + n_deps = pkg_has_installed_dependents(p, &dependents); + n_deps--; /* don't count old_pkg */ + + if (n_deps == 0) { + opkg_msg(NOTICE, "%s was autoinstalled and is " + "now orphaned, removing.\n", + p->name); + + /* p has one installed dependency (old_pkg), + * which we need to ignore during removal. */ + p->state_flag |= SF_REPLACE; + + r = opkg_remove_pkg(p, 0); + if (!err) + err = r; + } else + opkg_msg(INFO, "%s was autoinstalled and is " + "still required by %d " + "installed packages.\n", + p->name, n_deps); + + } + } + + return err; +} + +/* returns number of installed replacees */ +static int +pkg_get_installed_replacees(pkg_t *pkg, pkg_vec_t *installed_replacees) +{ + abstract_pkg_t **replaces = pkg->replaces; + int replaces_count = pkg->replaces_count; + int i, j; + for (i = 0; i < replaces_count; i++) { + abstract_pkg_t *ab_pkg = replaces[i]; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + if (pkg_vec) { + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *replacee = pkg_vec->pkgs[j]; + if (!pkg_conflicts(pkg, replacee)) + continue; + if (replacee->state_status == SS_INSTALLED) { + pkg_vec_insert(installed_replacees, replacee); + } + } + } + } + return installed_replacees->len; +} + +static int +pkg_remove_installed_replacees(pkg_vec_t *replacees) +{ + int i; + int replaces_count = replacees->len; + for (i = 0; i < replaces_count; i++) { + pkg_t *replacee = replacees->pkgs[i]; + int err; + replacee->state_flag |= SF_REPLACE; /* flag it so remove won't complain */ + err = opkg_remove_pkg(replacee, 0); + if (err) + return err; + } + return 0; +} + +/* to unwind the removal: make sure they are installed */ +static int +pkg_remove_installed_replacees_unwind(pkg_vec_t *replacees) +{ + int i, err; + int replaces_count = replacees->len; + for (i = 0; i < replaces_count; i++) { + pkg_t *replacee = replacees->pkgs[i]; + if (replacee->state_status != SS_INSTALLED) { + opkg_msg(DEBUG2, "Calling opkg_install_pkg.\n"); + err = opkg_install_pkg(replacee, 0); + if (err) + return err; + } + } + return 0; +} + +/* compares versions of pkg and old_pkg, returns 0 if OK to proceed with installation of pkg, 1 otherwise */ +static int +opkg_install_check_downgrade(pkg_t *pkg, pkg_t *old_pkg, int message) +{ + if (old_pkg) { + char message_out[15]; + char *old_version = pkg_version_str_alloc(old_pkg); + char *new_version = pkg_version_str_alloc(pkg); + int cmp = pkg_compare_versions(old_pkg, pkg); + int rc = 0; + + memset(message_out,'\x0',15); + strncpy (message_out,"Upgrading ",strlen("Upgrading ")); + if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */ + cmp = -1 ; /* then we force opkg to downgrade */ + strncpy (message_out,"Downgrading ",strlen("Downgrading ")); /* We need to use a value < 0 because in the 0 case we are asking to */ + /* reinstall, and some check could fail asking the "force-reinstall" option */ + } + + if (cmp > 0) { + if(!conf->download_only) + opkg_msg(NOTICE, + "Not downgrading package %s on %s from %s to %s.\n", + old_pkg->name, old_pkg->dest->name, old_version, new_version); + rc = 1; + } else if (cmp < 0) { + if(!conf->download_only) + opkg_msg(NOTICE, "%s%s on %s from %s to %s...\n", + message_out, pkg->name, old_pkg->dest->name, old_version, new_version); + pkg->dest = old_pkg->dest; + rc = 0; + } else /* cmp == 0 */ { + if(!conf->download_only) + opkg_msg(NOTICE, "%s (%s) already install on %s.\n", + pkg->name, new_version, old_pkg->dest->name); + rc = 1; + } + free(old_version); + free(new_version); + return rc; + } else { + char message_out[15] ; + memset(message_out,'\x0',15); + if ( message ) + strncpy( message_out,"Upgrading ",strlen("Upgrading ") ); + else + strncpy( message_out,"Installing ",strlen("Installing ") ); + char *version = pkg_version_str_alloc(pkg); + + if(!conf->download_only) + opkg_msg(NOTICE, "%s%s (%s) to %s...\n", message_out, + pkg->name, version, pkg->dest->name); + free(version); + } + return 0; +} + + +static int +prerm_upgrade_old_pkg(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + + 1. If a version of the package is already installed, call + old-prerm upgrade new-version + 2. If the script runs but exits with a non-zero exit status + new-prerm failed-upgrade old-version + Error unwind, for both the above cases: + old-postinst abort-upgrade new-version + */ + return 0; +} + +static int +prerm_upgrade_old_pkg_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + (See prerm_upgrade_old_package for details) + */ + return 0; +} + +static int +prerm_deconfigure_conflictors(pkg_t *pkg, pkg_vec_t *conflictors) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + 2. If a 'conflicting' package is being removed at the same time: + 1. If any packages depended on that conflicting package and + --auto-deconfigure is specified, call, for each such package: + deconfigured's-prerm deconfigure \ + in-favour package-being-installed version \ + removing conflicting-package version + Error unwind: + deconfigured's-postinst abort-deconfigure \ + in-favour package-being-installed-but-failed version \ + removing conflicting-package version + + The deconfigured packages are marked as requiring + configuration, so that if --install is used they will be + configured again if possible. + 2. To prepare for removal of the conflicting package, call: + conflictor's-prerm remove in-favour package new-version + Error unwind: + conflictor's-postinst abort-remove in-favour package new-version + */ + return 0; +} + +static int +prerm_deconfigure_conflictors_unwind(pkg_t *pkg, pkg_vec_t *conflictors) +{ + /* DPKG_INCOMPATIBILITY: dpkg does some things here that we don't + do yet. Do we care? (See prerm_deconfigure_conflictors for + details) */ + return 0; +} + +static int +preinst_configure(pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + char *preinst_args; + + if (old_pkg) { + char *old_version = pkg_version_str_alloc(old_pkg); + sprintf_alloc(&preinst_args, "upgrade %s", old_version); + free(old_version); + } else if (pkg->state_status == SS_CONFIG_FILES) { + char *pkg_version = pkg_version_str_alloc(pkg); + sprintf_alloc(&preinst_args, "install %s", pkg_version); + free(pkg_version); + } else { + preinst_args = xstrdup("install"); + } + + err = pkg_run_script(pkg, "preinst", preinst_args); + if (err) { + opkg_msg(ERROR, "Aborting installation of %s.\n", pkg->name); + return -1; + } + + free(preinst_args); + + return 0; +} + +static int +preinst_configure_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does the following error unwind, should we? + pkg->postrm abort-upgrade old-version + OR pkg->postrm abort-install old-version + OR pkg->postrm abort-install + */ + return 0; +} + +static char * +backup_filename_alloc(const char *file_name) +{ + char *backup; + + sprintf_alloc(&backup, "%s%s", file_name, OPKG_BACKUP_SUFFIX); + + return backup; +} + + +static int +backup_make_backup(const char *file_name) +{ + int err; + char *backup; + + backup = backup_filename_alloc(file_name); + err = file_copy(file_name, backup); + if (err) { + opkg_msg(ERROR, "Failed to copy %s to %s\n", + file_name, backup); + } + + free(backup); + + return err; +} + +static int +backup_exists_for(const char *file_name) +{ + int ret; + char *backup; + + backup = backup_filename_alloc(file_name); + + ret = file_exists(backup); + + free(backup); + + return ret; +} + +static int +backup_remove(const char *file_name) +{ + char *backup; + + backup = backup_filename_alloc(file_name); + unlink(backup); + free(backup); + + return 0; +} + +static int +backup_modified_conffiles(pkg_t *pkg, pkg_t *old_pkg) +{ + int err; + conffile_list_elt_t *iter; + conffile_t *cf; + + if (conf->noaction) return 0; + + /* Backup all modified conffiles */ + if (old_pkg) { + for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { + char *cf_name; + + cf = iter->data; + cf_name = root_filename_alloc(cf->name); + + /* Don't worry if the conffile is just plain gone */ + if (file_exists(cf_name) && conffile_has_been_modified(cf)) { + err = backup_make_backup(cf_name); + if (err) { + return err; + } + } + free(cf_name); + } + } + + /* Backup all conffiles that were not conffiles in old_pkg */ + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + char *cf_name; + cf = (conffile_t *)iter->data; + cf_name = root_filename_alloc(cf->name); + /* Ignore if this was a conffile in old_pkg as well */ + if (pkg_get_conffile(old_pkg, cf->name)) { + continue; + } + + if (file_exists(cf_name) && (! backup_exists_for(cf_name))) { + err = backup_make_backup(cf_name); + if (err) { + return err; + } + } + free(cf_name); + } + + return 0; +} + +static int +backup_modified_conffiles_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + conffile_list_elt_t *iter; + + if (old_pkg) { + for (iter = nv_pair_list_first(&old_pkg->conffiles); iter; iter = nv_pair_list_next(&old_pkg->conffiles, iter)) { + backup_remove(((nv_pair_t *)iter->data)->name); + } + } + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + backup_remove(((nv_pair_t *)iter->data)->name); + } + + return 0; +} + + +static int +check_data_file_clashes(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + opkg takes a slightly different approach than dpkg at this + point. dpkg installs each file in the new package while + creating a backup for any file that is replaced, (so that it + can unwind if necessary). To avoid complexity and redundant + storage, opkg doesn't do any installation until later, (at the + point at which dpkg removes the backups. + + But, we do have to check for data file clashes, since after + installing a package with a file clash, removing either of the + packages involved in the clash has the potential to break the + other package. + */ + str_list_t *files_list; + str_list_elt_t *iter, *niter; + char *filename; + int clashes = 0; + + files_list = pkg_get_installed_files(pkg); + if (files_list == NULL) + return -1; + + for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); + iter; + iter = niter, niter = str_list_next(files_list, iter)) { + filename = (char *) iter->data; + if (file_exists(filename) && (! file_is_dir(filename))) { + pkg_t *owner; + pkg_t *obs; + + if (backup_exists_for(filename)) { + continue; + } + + /* Pre-existing files are OK if force-overwrite was asserted. */ + if (conf->force_overwrite) { + /* but we need to change who owns this file */ + file_hash_set_file_owner(filename, pkg); + continue; + } + + owner = file_hash_get_file_owner(filename); + + /* Pre-existing files are OK if owned by the pkg being upgraded. */ + if (owner && old_pkg) { + if (strcmp(owner->name, old_pkg->name) == 0) { + continue; + } + } + + /* Pre-existing files are OK if owned by a package replaced by new pkg. */ + if (owner) { + opkg_msg(DEBUG2, "Checking replaces for %s in package %s\n", + filename, owner->name); + if (pkg_replaces(pkg, owner)) { + continue; + } +/* If the file that would be installed is owned by the same package, ( as per a reinstall or similar ) + then it's ok to overwrite. */ + if (strcmp(owner->name,pkg->name)==0){ + opkg_msg(INFO, "Replacing pre-existing file %s" + " owned by package %s\n", + filename, owner->name); + continue; + } + } + + /* Pre-existing files are OK if they are obsolete */ + obs = hash_table_get(&conf->obs_file_hash, filename); + if (obs) { + opkg_msg(INFO, "Pre-exiting file %s is obsolete." + " obs_pkg=%s\n", + filename, obs->name); + continue; + } + + /* We have found a clash. */ + opkg_msg(ERROR, "Package %s wants to install file %s\n" + "\tBut that file is already provided by package ", + pkg->name, filename); + if (owner) { + opkg_message(ERROR, "%s\n", owner->name); + } else { + opkg_message(ERROR, "<no package>\n" + "Please move this file out of the way and try again.\n"); + } + clashes++; + } + } + pkg_free_installed_files(pkg); + + return clashes; +} + +/* + * XXX: This function sucks, as does the below comment. + */ +static int +check_data_file_clashes_change(pkg_t *pkg, pkg_t *old_pkg) +{ + /* Basically that's the worst hack I could do to be able to change ownership of + file list, but, being that we have no way to unwind the mods, due to structure + of hash table, probably is the quickest hack too, whishing it would not slow-up thing too much. + What we do here is change the ownership of file in hash if a replace ( or similar events + happens ) + Only the action that are needed to change name should be considered. + @@@ To change after 1.0 release. + */ + str_list_t *files_list; + str_list_elt_t *iter, *niter; + + char *root_filename = NULL; + + files_list = pkg_get_installed_files(pkg); + if (files_list == NULL) + return -1; + + for (iter = str_list_first(files_list), niter = str_list_next(files_list, iter); + iter; + iter = niter, niter = str_list_next(files_list, niter)) { + char *filename = (char *) iter->data; + if (root_filename) { + free(root_filename); + root_filename = NULL; + } + root_filename = root_filename_alloc(filename); + if (file_exists(root_filename) && (! file_is_dir(root_filename))) { + pkg_t *owner; + + owner = file_hash_get_file_owner(filename); + + if (conf->force_overwrite) { + /* but we need to change who owns this file */ + file_hash_set_file_owner(filename, pkg); + continue; + } + + + /* Pre-existing files are OK if owned by a package replaced by new pkg. */ + if (owner) { + if (pkg_replaces(pkg, owner)) { +/* It's now time to change the owner of that file. + It has been "replaced" from the new "Replaces", then I need to inform lists file about that. */ + opkg_msg(INFO, "Replacing pre-existing file %s " + "owned by package %s\n", + filename, owner->name); + file_hash_set_file_owner(filename, pkg); + continue; + } + } + + } + } + if (root_filename) { + free(root_filename); + root_filename = NULL; + } + pkg_free_installed_files(pkg); + + return 0; +} + +static int +check_data_file_clashes_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* Nothing to do since check_data_file_clashes doesn't change state */ + return 0; +} + +static int +postrm_upgrade_old_pkg(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: dpkg does the following here, should we? + 1. If the package is being upgraded, call + old-postrm upgrade new-version + 2. If this fails, attempt: + new-postrm failed-upgrade old-version + Error unwind, for both cases: + old-preinst abort-upgrade new-version */ + return 0; +} + +static int +postrm_upgrade_old_pkg_unwind(pkg_t *pkg, pkg_t *old_pkg) +{ + /* DPKG_INCOMPATIBILITY: + dpkg does some things here that we don't do yet. Do we care? + (See postrm_upgrade_old_pkg for details) + */ + return 0; +} + +static int +remove_obsolesced_files(pkg_t *pkg, pkg_t *old_pkg) +{ + int err = 0; + str_list_t *old_files; + str_list_elt_t *of; + str_list_t *new_files; + str_list_elt_t *nf; + hash_table_t new_files_table; + + old_files = pkg_get_installed_files(old_pkg); + if (old_files == NULL) + return -1; + + new_files = pkg_get_installed_files(pkg); + if (new_files == NULL) { + pkg_free_installed_files(old_pkg); + return -1; + } + + new_files_table.entries = NULL; + hash_table_init("new_files" , &new_files_table, 20); + for (nf = str_list_first(new_files); nf; nf = str_list_next(new_files, nf)) { + if (nf && nf->data) + hash_table_insert(&new_files_table, nf->data, nf->data); + } + + for (of = str_list_first(old_files); of; of = str_list_next(old_files, of)) { + pkg_t *owner; + char *old, *new; + old = (char *)of->data; + new = (char *) hash_table_get (&new_files_table, old); + if (new) + continue; + + if (file_is_dir(old)) { + continue; + } + owner = file_hash_get_file_owner(old); + if (owner != old_pkg) { + /* in case obsolete file no longer belongs to old_pkg */ + continue; + } + + /* old file is obsolete */ + opkg_msg(NOTICE, "Removing obsolete file %s.\n", old); + if (!conf->noaction) { + err = unlink(old); + if (err) { + opkg_perror(ERROR, "unlinking %s failed", old); + } + } + } + + hash_table_deinit(&new_files_table); + pkg_free_installed_files(old_pkg); + pkg_free_installed_files(pkg); + + return err; +} + +static int +install_maintainer_scripts(pkg_t *pkg, pkg_t *old_pkg) +{ + int ret; + char *prefix; + + sprintf_alloc(&prefix, "%s.", pkg->name); + ret = pkg_extract_control_files_to_dir_with_prefix(pkg, + pkg->dest->info_dir, + prefix); + free(prefix); + return ret; +} + +static int +remove_disappeared(pkg_t *pkg) +{ + /* DPKG_INCOMPATIBILITY: + This is a fairly sophisticated dpkg operation. Shall we + skip it? */ + + /* Any packages all of whose files have been overwritten during the + installation, and which aren't required for dependencies, are + considered to have been removed. For each such package + 1. disappearer's-postrm disappear overwriter overwriter-version + 2. The package's maintainer scripts are removed + 3. It is noted in the status database as being in a sane state, + namely not installed (any conffiles it may have are ignored, + rather than being removed by dpkg). Note that disappearing + packages do not have their prerm called, because dpkg doesn't + know in advance that the package is going to vanish. + */ + return 0; +} + +static int +install_data_files(pkg_t *pkg) +{ + int err; + + /* opkg takes a slightly different approach to data file backups + than dpkg. Rather than removing backups at this point, we + actually do the data file installation now. See comments in + check_data_file_clashes() for more details. */ + + opkg_msg(INFO, "Extracting data files to %s.\n", pkg->dest->root_dir); + err = pkg_extract_data_files_to_dir(pkg, pkg->dest->root_dir); + if (err) { + return err; + } + + /* The "Essential" control field may only be present in the control + * file and not in the Packages list. Ensure we capture it regardless. + * + * XXX: This should be fixed outside of opkg, in the Package list. + */ + set_flags_from_control(pkg) ; + + opkg_msg(DEBUG, "Calling pkg_write_filelist.\n"); + err = pkg_write_filelist(pkg); + if (err) + return err; + + /* XXX: FEATURE: opkg should identify any files which existed + before installation and which were overwritten, (see + check_data_file_clashes()). What it must do is remove any such + files from the filelist of the old package which provided the + file. Otherwise, if the old package were removed at some point + it would break the new package. Removing the new package will + also break the old one, but this cannot be helped since the old + package's file has already been deleted. This is the importance + of check_data_file_clashes(), and only allowing opkg to install + a clashing package with a user force. */ + + return 0; +} + +static int +resolve_conffiles(pkg_t *pkg) +{ + conffile_list_elt_t *iter; + conffile_t *cf; + char *cf_backup; + char *md5sum; + + if (conf->noaction) return 0; + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + char *root_filename; + cf = (conffile_t *)iter->data; + root_filename = root_filename_alloc(cf->name); + + /* Might need to initialize the md5sum for each conffile */ + if (cf->value == NULL) { + cf->value = file_md5sum_alloc(root_filename); + } + + if (!file_exists(root_filename)) { + free(root_filename); + continue; + } + + cf_backup = backup_filename_alloc(root_filename); + + if (file_exists(cf_backup)) { + /* Let's compute md5 to test if files are changed */ + md5sum = file_md5sum_alloc(cf_backup); + if (md5sum && cf->value && strcmp(cf->value,md5sum) != 0 ) { + if (conf->force_maintainer) { + opkg_msg(NOTICE, "Conffile %s using maintainer's setting.\n", + cf_backup); + } else { + char *new_conffile; + sprintf_alloc(&new_conffile, "%s-opkg", root_filename); + opkg_msg(ERROR, "Existing conffile %s " + "is different from the conffile in the new package." + " The new conffile will be placed at %s.\n", + root_filename, new_conffile); + rename(root_filename, new_conffile); + rename(cf_backup, root_filename); + free(new_conffile); + } + } + unlink(cf_backup); + if (md5sum) + free(md5sum); + } + + free(cf_backup); + free(root_filename); + } + + return 0; +} + + +int +opkg_install_by_name(const char *pkg_name) +{ + int cmp; + pkg_t *old, *new; + char *old_version, *new_version; + + old = pkg_hash_fetch_installed_by_name(pkg_name); + if (old) + opkg_msg(DEBUG2, "Old versions from pkg_hash_fetch %s.\n", + old->version); + + new = pkg_hash_fetch_best_installation_candidate_by_name(pkg_name); + if (new == NULL) { + opkg_msg(NOTICE, "Unknown package '%s'.\n", pkg_name); + return -1; + } + + opkg_msg(DEBUG2, "Versions from pkg_hash_fetch:"); + if ( old ) + opkg_message(DEBUG2, " old %s ", old->version); + opkg_message(DEBUG2, " new %s\n", new->version); + + new->state_flag |= SF_USER; + if (old) { + old_version = pkg_version_str_alloc(old); + new_version = pkg_version_str_alloc(new); + + cmp = pkg_compare_versions(old, new); + if ( (conf->force_downgrade==1) && (cmp > 0) ){ /* We've been asked to allow downgrade and version is precedent */ + opkg_msg(DEBUG, "Forcing downgrade\n"); + cmp = -1 ; /* then we force opkg to downgrade */ + /* We need to use a value < 0 because in the 0 case we are asking to */ + /* reinstall, and some check could fail asking the "force-reinstall" option */ + } + opkg_msg(DEBUG, "Comparing visible versions of pkg %s:" + "\n\t%s is installed " + "\n\t%s is available " + "\n\t%d was comparison result\n", + pkg_name, old_version, new_version, cmp); + if (cmp == 0) { + opkg_msg(NOTICE, + "Package %s (%s) installed in %s is up to date.\n", + old->name, old_version, old->dest->name); + free(old_version); + free(new_version); + return 0; + } else if (cmp > 0) { + opkg_msg(NOTICE, + "Not downgrading package %s on %s from %s to %s.\n", + old->name, old->dest->name, old_version, new_version); + free(old_version); + free(new_version); + return 0; + } else if (cmp < 0) { + new->dest = old->dest; + old->state_want = SW_DEINSTALL; + } + free(old_version); + free(new_version); + } + + opkg_msg(DEBUG2,"Calling opkg_install_pkg.\n"); + return opkg_install_pkg(new, 0); +} + +/** + * @brief Really install a pkg_t + */ +int +opkg_install_pkg(pkg_t *pkg, int from_upgrade) +{ + int err = 0; + int message = 0; + pkg_t *old_pkg = NULL; + pkg_vec_t *replacees; + abstract_pkg_t *ab_pkg = NULL; + int old_state_flag; + char* file_md5; +#ifdef HAVE_SHA256 + char* file_sha256; +#endif + sigset_t newset, oldset; + + if ( from_upgrade ) + message = 1; /* Coming from an upgrade, and should change the output message */ + + opkg_msg(DEBUG2, "Calling pkg_arch_supported.\n"); + + if (!pkg_arch_supported(pkg)) { + opkg_msg(ERROR, "INTERNAL ERROR: architecture %s for pkg %s is unsupported.\n", + pkg->architecture, pkg->name); + return -1; + } + if (pkg->state_status == SS_INSTALLED && conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + + opkg_msg(NOTICE, "Package %s is already installed on %s.\n", + pkg->name, pkg->dest->name); + return 0; + } + + if (pkg->dest == NULL) { + pkg->dest = conf->default_dest; + } + + old_pkg = pkg_hash_fetch_installed_by_name(pkg->name); + + err = opkg_install_check_downgrade(pkg, old_pkg, message); + if (err) + return -1; + + pkg->state_want = SW_INSTALL; + if (old_pkg){ + old_pkg->state_want = SW_DEINSTALL; /* needed for check_data_file_clashes of dependencies */ + } + + err = check_conflicts_for(pkg); + if (err) + return -1; + + /* this setup is to remove the upgrade scenario in the end when + installing pkg A, A deps B & B deps on A. So both B and A are + installed. Then A's installation is started resulting in an + uncecessary upgrade */ + if (pkg->state_status == SS_INSTALLED) + return 0; + + err = verify_pkg_installable(pkg); + if (err) + return -1; + + if (pkg->local_filename == NULL) { + if(!conf->cache && conf->download_only){ + char cwd[4096]; + if(getcwd(cwd, sizeof(cwd)) != NULL) + err = opkg_download_pkg(pkg, cwd); + else + return -1; + } else { + err = opkg_download_pkg(pkg, conf->tmp_dir); + } + if (err) { + opkg_msg(ERROR, "Failed to download %s. " + "Perhaps you need to run 'opkg update'?\n", + pkg->name); + return -1; + } + } + + /* check that the repository is valid */ + #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL) + char *list_file_name, *sig_file_name, *lists_dir; + + /* check to ensure the package has come from a repository */ + if (conf->check_signature && pkg->src) + { + sprintf_alloc (&lists_dir, "%s", + (conf->restrict_to_default_dest) + ? conf->default_dest->lists_dir + : conf->lists_dir); + sprintf_alloc (&list_file_name, "%s/%s", lists_dir, pkg->src->name); + sprintf_alloc (&sig_file_name, "%s/%s.sig", lists_dir, pkg->src->name); + + if (file_exists (sig_file_name)) + { + if (opkg_verify_file (list_file_name, sig_file_name)){ + opkg_msg(ERROR, "Failed to verify the signature of %s.\n", + list_file_name); + return -1; + } + }else{ + opkg_msg(ERROR, "Signature file is missing for %s. " + "Perhaps you need to run 'opkg update'?\n", + pkg->name); + return -1; + } + + free (lists_dir); + free (list_file_name); + free (sig_file_name); + } + #endif + + /* Check for md5 values */ + if (pkg->md5sum) + { + file_md5 = file_md5sum_alloc(pkg->local_filename); + if (file_md5 && strcmp(file_md5, pkg->md5sum)) + { + opkg_msg(ERROR, "Package %s md5sum mismatch. " + "Either the opkg or the package index are corrupt. " + "Try 'opkg update'.\n", + pkg->name); + free(file_md5); + return -1; + } + if (file_md5) + free(file_md5); + } + +#ifdef HAVE_SHA256 + /* Check for sha256 value */ + if(pkg->sha256sum) + { + file_sha256 = file_sha256sum_alloc(pkg->local_filename); + if (file_sha256 && strcmp(file_sha256, pkg->sha256sum)) + { + opkg_msg(ERROR, "Package %s sha256sum mismatch. " + "Either the opkg or the package index are corrupt. " + "Try 'opkg update'.\n", + pkg->name); + free(file_sha256); + return -1; + } + if (file_sha256) + free(file_sha256); + } +#endif + if(conf->download_only) { + if (conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + } + return 0; + } + + if (pkg->tmp_unpack_dir == NULL) { + if (unpack_pkg_control_files(pkg) == -1) { + opkg_msg(ERROR, "Failed to unpack control files from %s.\n", + pkg->local_filename); + return -1; + } + } + + err = update_file_ownership(pkg, old_pkg); + if (err) + return -1; + + if (conf->nodeps == 0) { + err = satisfy_dependencies_for(pkg); + if (err) + return -1; + if (pkg->state_status == SS_UNPACKED) + /* Circular dependency has installed it for us. */ + return 0; + } + + replacees = pkg_vec_alloc(); + pkg_get_installed_replacees(pkg, replacees); + + /* this next section we do with SIGINT blocked to prevent inconsistency between opkg database and filesystem */ + + sigemptyset(&newset); + sigaddset(&newset, SIGINT); + sigprocmask(SIG_BLOCK, &newset, &oldset); + + opkg_state_changed++; + pkg->state_flag |= SF_FILELIST_CHANGED; + + if (old_pkg) + pkg_remove_orphan_dependent(pkg, old_pkg); + + /* XXX: BUG: we really should treat replacement more like an upgrade + * Instead, we're going to remove the replacees + */ + err = pkg_remove_installed_replacees(replacees); + if (err) + goto UNWIND_REMOVE_INSTALLED_REPLACEES; + + err = prerm_upgrade_old_pkg(pkg, old_pkg); + if (err) + goto UNWIND_PRERM_UPGRADE_OLD_PKG; + + err = prerm_deconfigure_conflictors(pkg, replacees); + if (err) + goto UNWIND_PRERM_DECONFIGURE_CONFLICTORS; + + err = preinst_configure(pkg, old_pkg); + if (err) + goto UNWIND_PREINST_CONFIGURE; + + err = backup_modified_conffiles(pkg, old_pkg); + if (err) + goto UNWIND_BACKUP_MODIFIED_CONFFILES; + + err = check_data_file_clashes(pkg, old_pkg); + if (err) + goto UNWIND_CHECK_DATA_FILE_CLASHES; + + err = postrm_upgrade_old_pkg(pkg, old_pkg); + if (err) + goto UNWIND_POSTRM_UPGRADE_OLD_PKG; + + if (conf->noaction) + return 0; + + /* point of no return: no unwinding after this */ + if (old_pkg) { + old_pkg->state_want = SW_DEINSTALL; + + if (old_pkg->state_flag & SF_NOPRUNE) { + opkg_msg(INFO, "Not removing obsolesced files because " + "package %s marked noprune.\n", + old_pkg->name); + } else { + opkg_msg(INFO, "Removing obsolesced files for %s\n", + old_pkg->name); + if (remove_obsolesced_files(pkg, old_pkg)) { + opkg_msg(ERROR, "Failed to determine " + "obsolete files from previously " + "installed %s\n", old_pkg->name); + } + } + + /* removing files from old package, to avoid ghost files */ + remove_data_files_and_list(old_pkg); + remove_maintainer_scripts(old_pkg); + + /* maintain the "Auto-Installed: yes" flag */ + pkg->auto_installed = old_pkg->auto_installed; + } + + + opkg_msg(INFO, "Installing maintainer scripts.\n"); + if (install_maintainer_scripts(pkg, old_pkg)) { + opkg_msg(ERROR, "Failed to extract maintainer scripts for %s." + " Package debris may remain!\n", + pkg->name); + goto pkg_is_hosed; + } + + /* the following just returns 0 */ + remove_disappeared(pkg); + + opkg_msg(INFO, "Installing data files for %s.\n", pkg->name); + + if (install_data_files(pkg)) { + opkg_msg(ERROR, "Failed to extract data files for %s. " + "Package debris may remain!\n", + pkg->name); + goto pkg_is_hosed; + } + + err = check_data_file_clashes_change(pkg, old_pkg); + if (err) { + opkg_msg(ERROR, "check_data_file_clashes_change() failed for " + "for files belonging to %s.\n", + pkg->name); + } + + opkg_msg(INFO, "Resolving conf files for %s\n", pkg->name); + resolve_conffiles(pkg); + + pkg->state_status = SS_UNPACKED; + old_state_flag = pkg->state_flag; + pkg->state_flag &= ~SF_PREFER; + opkg_msg(DEBUG, "pkg=%s old_state_flag=%x state_flag=%x\n", + pkg->name, old_state_flag, pkg->state_flag); + + if (old_pkg) + old_pkg->state_status = SS_NOT_INSTALLED; + + time(&pkg->installed_time); + + ab_pkg = pkg->parent; + if (ab_pkg) + ab_pkg->state_status = pkg->state_status; + + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + pkg_vec_free (replacees); + return 0; + + + UNWIND_POSTRM_UPGRADE_OLD_PKG: + postrm_upgrade_old_pkg_unwind(pkg, old_pkg); + UNWIND_CHECK_DATA_FILE_CLASHES: + check_data_file_clashes_unwind(pkg, old_pkg); + UNWIND_BACKUP_MODIFIED_CONFFILES: + backup_modified_conffiles_unwind(pkg, old_pkg); + UNWIND_PREINST_CONFIGURE: + preinst_configure_unwind(pkg, old_pkg); + UNWIND_PRERM_DECONFIGURE_CONFLICTORS: + prerm_deconfigure_conflictors_unwind(pkg, replacees); + UNWIND_PRERM_UPGRADE_OLD_PKG: + prerm_upgrade_old_pkg_unwind(pkg, old_pkg); + UNWIND_REMOVE_INSTALLED_REPLACEES: + pkg_remove_installed_replacees_unwind(replacees); + +pkg_is_hosed: + sigprocmask(SIG_UNBLOCK, &newset, &oldset); + + pkg_vec_free (replacees); + return -1; +} diff --git a/src/libopkg/opkg_install.h b/src/libopkg/opkg_install.h new file mode 100644 index 0000000..eaffff8 --- /dev/null +++ b/src/libopkg/opkg_install.h @@ -0,0 +1,27 @@ +/* opkg_install.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_INSTALL_H +#define OPKG_INSTALL_H + +#include "pkg.h" +#include "opkg_conf.h" + +int opkg_install_by_name(const char *pkg_name); +int opkg_install_pkg(pkg_t *pkg, int from_upgrading); + +#endif diff --git a/src/libopkg/opkg_message.c b/src/libopkg/opkg_message.c new file mode 100644 index 0000000..7114e3a --- /dev/null +++ b/src/libopkg/opkg_message.c @@ -0,0 +1,121 @@ +/* opkg_message.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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, 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. +*/ + +#include <stdio.h> + +#include "opkg_conf.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + +struct errlist { + char *errmsg; + struct errlist *next; +}; + +static struct errlist *error_list_head, *error_list_tail; + +static void +push_error_list(char *msg) +{ + struct errlist *e; + + e = xcalloc(1, sizeof(struct errlist)); + e->errmsg = xstrdup(msg); + e->next = NULL; + + if (error_list_head) { + error_list_tail->next = e; + error_list_tail = e; + } else { + error_list_head = error_list_tail = e; + } +} + +void +free_error_list(void) +{ + struct errlist *err, *err_tmp; + + err = error_list_head; + while (err != NULL) { + free(err->errmsg); + err_tmp = err; + err = err->next; + free(err_tmp); + } +} + +void +print_error_list(void) +{ + struct errlist *err = error_list_head; + + if (err) { + printf("Collected errors:\n"); + /* Here we print the errors collected and free the list */ + while (err != NULL) { + printf(" * %s", err->errmsg); + err = err->next; + } + } +} + +void +opkg_message (message_level_t level, const char *fmt, ...) +{ + va_list ap; + + if (conf->verbosity < level) + return; + + if (conf->opkg_vmessage) { + /* Pass the message to libopkg users. */ + va_start (ap, fmt); + conf->opkg_vmessage(level, fmt, ap); + va_end (ap); + return; + } + + va_start (ap, fmt); + + if (level == ERROR) { +#define MSG_LEN 4096 + char msg[MSG_LEN]; + int ret; + ret = vsnprintf(msg, MSG_LEN, fmt, ap); + if (ret < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vsnprintf.\n", + __FUNCTION__); + va_end (ap); + exit(EXIT_FAILURE); + } + if (ret >= MSG_LEN) { + fprintf(stderr, "%s: Message truncated.\n", + __FUNCTION__); + } + push_error_list(msg); + } else { + if (vprintf(fmt, ap) < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vprintf.\n", + __FUNCTION__); + exit(EXIT_FAILURE); + } + } + + va_end (ap); +} diff --git a/src/libopkg/opkg_message.h b/src/libopkg/opkg_message.h new file mode 100644 index 0000000..4fa2a0b --- /dev/null +++ b/src/libopkg/opkg_message.h @@ -0,0 +1,47 @@ +/* opkg_message.h - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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, 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. +*/ + +#ifndef _OPKG_MESSAGE_H_ +#define _OPKG_MESSAGE_H_ + +#include <string.h> +#include <errno.h> + +typedef enum { + ERROR, /* error conditions */ + NOTICE, /* normal but significant condition */ + INFO, /* informational message */ + DEBUG, /* debug level message */ + DEBUG2, /* more debug level message */ +} message_level_t; + +void free_error_list(void); +void print_error_list(void); +void opkg_message(message_level_t level, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +#define opkg_msg(l, fmt, args...) \ + do { \ + if (l == NOTICE) \ + opkg_message(l, fmt, ##args); \ + else \ + opkg_message(l, "%s: "fmt, __FUNCTION__, ##args); \ + } while (0) + +#define opkg_perror(l, fmt, args...) \ + opkg_msg(l, fmt": %s.\n", ##args, strerror(errno)) + +#endif /* _OPKG_MESSAGE_H_ */ diff --git a/src/libopkg/opkg_pathfinder.c b/src/libopkg/opkg_pathfinder.c new file mode 100644 index 0000000..bf7dab6 --- /dev/null +++ b/src/libopkg/opkg_pathfinder.c @@ -0,0 +1,100 @@ +/* vi: set noexpandtab sw=4 sts=4: */ +/* opkg_pathfinder.c - the opkg package management system + + Copyright (C) 2009 Camille Moncelier <moncelier@devlife.org> + + 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, 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. +*/ +#include "config.h" + +#include <openssl/ssl.h> +#include <libpathfinder.h> +#include <stdlib.h> +#if defined(HAVE_SSLCURL) +#include <curl/curl.h> +#endif + +#include "libbb/libbb.h" +#include "opkg_message.h" + +#if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL) +/* + * This callback is called instead of X509_verify_cert to perform path + * validation on a certificate using pathfinder. + * + */ +static int pathfinder_verify_callback(X509_STORE_CTX *ctx, void *arg) +{ + char *errmsg; + const char *hex = "0123456789ABCDEF"; + size_t size = i2d_X509(ctx->cert, NULL); + unsigned char *keybuf, *iend; + iend = keybuf = xmalloc(size); + i2d_X509(ctx->cert, &iend); + char *certdata_str = xmalloc(size * 2 + 1); + unsigned char *cp = keybuf; + char *certdata_str_i = certdata_str; + while (cp < iend) + { + unsigned char ch = *cp++; + *certdata_str_i++ = hex[(ch >> 4) & 0xf]; + *certdata_str_i++ = hex[ch & 0xf]; + } + *certdata_str_i = 0; + free(keybuf); + + const char *policy = "2.5.29.32.0"; // anyPolicy + int validated = pathfinder_dbus_verify(certdata_str, policy, 0, 0, &errmsg); + + if (!validated) + opkg_msg(ERROR, "Path verification failed: %s.\n", errmsg); + + free(certdata_str); + free(errmsg); + + return validated; +} +#endif + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7) +{ + STACK_OF(X509) *signers; + int i, ret = 1; /* signers are verified by default */ + + signers = PKCS7_get0_signers(p7, NULL, 0); + + for(i = 0; i < sk_X509_num(signers); i++){ + X509_STORE_CTX ctx = { + .cert = sk_X509_value(signers, i), + }; + + if(!pathfinder_verify_callback(&ctx, NULL)){ + /* Signer isn't verified ! goto jail; */ + ret = 0; + break; + } + } + + sk_X509_free(signers); + return ret; +} +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm) { + + SSL_CTX * ctx = (SSL_CTX *) sslctx; + SSL_CTX_set_cert_verify_callback(ctx, pathfinder_verify_callback, parm); + + return CURLE_OK ; +} +#endif diff --git a/src/libopkg/opkg_pathfinder.h b/src/libopkg/opkg_pathfinder.h new file mode 100644 index 0000000..89bebbd --- /dev/null +++ b/src/libopkg/opkg_pathfinder.h @@ -0,0 +1,31 @@ +/* opkg_pathfinder.h - the opkg package management system + + + Copyright (C) 2009 Camille Moncelier <moncelier@devlife.org> + + 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, 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. +*/ + +#ifndef OPKG_PATHFINDER_H +#define OPKG_PATHFINDER_H + +#include "config.h" + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7); +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm); +#endif + + +#endif diff --git a/src/libopkg/opkg_remove.c b/src/libopkg/opkg_remove.c new file mode 100644 index 0000000..5f4219b --- /dev/null +++ b/src/libopkg/opkg_remove.c @@ -0,0 +1,450 @@ +/* opkg_remove.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> +#include <glob.h> +#include <unistd.h> + +#include "opkg_message.h" +#include "opkg_remove.h" +#include "opkg_cmd.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "libbb/libbb.h" + +/* + * Returns number of the number of packages depending on the packages provided by this package. + * Every package implicitly provides itself. + */ +int +pkg_has_installed_dependents(pkg_t *pkg, abstract_pkg_t *** pdependents) +{ + int nprovides = pkg->provides_count; + abstract_pkg_t **provides = pkg->provides; + unsigned int n_installed_dependents = 0; + int i; + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *providee = provides[i]; + abstract_pkg_t **dependers = providee->depended_upon_by; + abstract_pkg_t *dep_ab_pkg; + if (dependers == NULL) + continue; + while ((dep_ab_pkg = *dependers++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED || dep_ab_pkg->state_status == SS_UNPACKED){ + n_installed_dependents++; + } + } + + } + /* if caller requested the set of installed dependents */ + if (pdependents) { + int p = 0; + abstract_pkg_t **dependents = xcalloc((n_installed_dependents+1), sizeof(abstract_pkg_t *)); + + *pdependents = dependents; + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *providee = provides[i]; + abstract_pkg_t **dependers = providee->depended_upon_by; + abstract_pkg_t *dep_ab_pkg; + if (dependers == NULL) + continue; + while ((dep_ab_pkg = *dependers++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED && !(dep_ab_pkg->state_flag & SF_MARKED)) { + dependents[p++] = dep_ab_pkg; + dep_ab_pkg->state_flag |= SF_MARKED; + } + } + } + dependents[p] = NULL; + /* now clear the marks */ + for (i = 0; i < p; i++) { + abstract_pkg_t *dep_ab_pkg = dependents[i]; + dep_ab_pkg->state_flag &= ~SF_MARKED; + } + } + return n_installed_dependents; +} + +static int +opkg_remove_dependent_pkgs(pkg_t *pkg, abstract_pkg_t **dependents) +{ + int i; + int a; + int count; + pkg_vec_t *dependent_pkgs; + abstract_pkg_t * ab_pkg; + + if((ab_pkg = pkg->parent) == NULL){ + opkg_msg(ERROR, "Internal error: pkg %s isn't in hash table\n", + pkg->name); + return 0; + } + + if (dependents == NULL) + return 0; + + // here i am using the dependencies_checked + if (ab_pkg->dependencies_checked == 2) // variable to make out whether this package + return 0; // has already been encountered in the process + // of marking packages for removal - Karthik + ab_pkg->dependencies_checked = 2; + + i = 0; + count = 1; + dependent_pkgs = pkg_vec_alloc(); + + while (dependents [i] != NULL) { + abstract_pkg_t *dep_ab_pkg = dependents[i]; + + if (dep_ab_pkg->dependencies_checked == 2){ + i++; + continue; + } + if (dep_ab_pkg->state_status == SS_INSTALLED) { + for (a = 0; a < dep_ab_pkg->pkgs->len; a++) { + pkg_t *dep_pkg = dep_ab_pkg->pkgs->pkgs[a]; + if (dep_pkg->state_status == SS_INSTALLED) { + pkg_vec_insert(dependent_pkgs, dep_pkg); + count++; + } + } + } + i++; + /* 1 - to keep track of visited ab_pkgs when checking for possiblility of a broken removal of pkgs. + * 2 - to keep track of pkgs whose deps have been checked alrdy - Karthik */ + } + + if (count == 1) { + pkg_vec_free(dependent_pkgs); + return 0; + } + + + int err=0; + for (i = 0; i < dependent_pkgs->len; i++) { + err = opkg_remove_pkg(dependent_pkgs->pkgs[i],0); + if (err) + break; + } + pkg_vec_free(dependent_pkgs); + return err; +} + +static void +print_dependents_warning(pkg_t *pkg, abstract_pkg_t **dependents) +{ + abstract_pkg_t *dep_ab_pkg; + opkg_msg(ERROR, "Package %s is depended upon by packages:\n", pkg->name); + while ((dep_ab_pkg = *dependents++) != NULL) { + if (dep_ab_pkg->state_status == SS_INSTALLED) + opkg_msg(ERROR, "\t%s\n", dep_ab_pkg->name); + } + opkg_msg(ERROR, "These might cease to work if package %s is removed.\n\n", + pkg->name); + opkg_msg(ERROR, "Force removal of this package with --force-depends.\n"); + opkg_msg(ERROR, "Force removal of this package and its dependents\n"); + opkg_msg(ERROR, "with --force-removal-of-dependent-packages.\n"); +} + +/* + * Find and remove packages that were autoinstalled and are orphaned + * by the removal of pkg. + */ +static int +remove_autoinstalled(pkg_t *pkg) +{ + int i, j; + int err = 0; + int n_deps; + pkg_t *p; + struct compound_depend *cdep; + abstract_pkg_t **dependents; + + int count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count; i++) { + cdep = &pkg->depends[i]; + if (cdep->type != PREDEPEND + && cdep->type != DEPEND + && cdep->type != RECOMMEND) + continue; + for (j=0; j<cdep->possibility_count; j++) { + p = pkg_hash_fetch_installed_by_name( + cdep->possibilities[j]->pkg->name); + + /* If the package is not installed, this could have + * been a circular dependency and the package has + * already been removed. + */ + if (!p) + return -1; + + if (!p->auto_installed) + continue; + + n_deps = pkg_has_installed_dependents(p, &dependents); + if (n_deps == 0) { + opkg_msg(NOTICE, "%s was autoinstalled and is " + "now orphaned, removing.\n", + p->name); + if (opkg_remove_pkg(p, 0) != 0) { + err = -1; + } + } else + opkg_msg(INFO, "%s was autoinstalled and is " + "still required by %d " + "installed packages.\n", + p->name, n_deps); + + if (dependents) + free(dependents); + } + } + + return err; +} + +int +opkg_remove_pkg(pkg_t *pkg, int from_upgrade) +{ + int err; + abstract_pkg_t *parent_pkg = NULL; + +/* + * If called from an upgrade and not from a normal remove, + * ignore the essential flag. + */ + if (pkg->essential && !from_upgrade) { + if (conf->force_removal_of_essential_packages) { + opkg_msg(NOTICE, + "Removing essential package %s under your coercion.\n" + "\tIf your system breaks, you get to keep both pieces\n", + pkg->name); + } else { + opkg_msg(NOTICE, "Refusing to remove essential package %s.\n" + "\tRemoving an essential package may lead to an unusable system, but if\n" + "\tyou enjoy that kind of pain, you can force opkg to proceed against\n" + "\tits will with the option: --force-removal-of-essential-packages\n", + pkg->name); + return -1; + } + } + + if ((parent_pkg = pkg->parent) == NULL) + return 0; + + /* only attempt to remove dependent installed packages if + * force_depends is not specified or the package is being + * replaced. + */ + if (!conf->force_depends + && !(pkg->state_flag & SF_REPLACE)) { + abstract_pkg_t **dependents; + int has_installed_dependents = + pkg_has_installed_dependents(pkg, &dependents); + + if (has_installed_dependents) { + /* + * if this package is depended upon by others, then either we should + * not remove it or we should remove it and all of its dependents + */ + + if (!conf->force_removal_of_dependent_packages) { + print_dependents_warning(pkg, dependents); + free(dependents); + return -1; + } + + /* remove packages depending on this package - Karthik */ + err = opkg_remove_dependent_pkgs(pkg, dependents); + if (err) { + free(dependents); + return err; + } + } + if (dependents) + free(dependents); + } + + if (from_upgrade == 0) { + opkg_msg(NOTICE, "Removing package %s from %s...\n", + pkg->name, pkg->dest->name); + } + pkg->state_flag |= SF_FILELIST_CHANGED; + + pkg->state_want = SW_DEINSTALL; + opkg_state_changed++; + + if (pkg_run_script(pkg, "prerm", "remove") != 0) { + if (!conf->force_remove) { + opkg_msg(ERROR, "not removing package \"%s\", " + "prerm script failed\n", pkg->name); + opkg_msg(NOTICE, "You can force removal of packages with failed " + "prerm scripts with the option: \n" + "\t--force-remove\n"); + return -1; + } + } + + /* DPKG_INCOMPATIBILITY: dpkg is slightly different here. It + maintains an empty filelist rather than deleting it. That seems + like a big pain, and I don't see that that should make a big + difference, but for anyone who wants tighter compatibility, + feel free to fix this. */ + remove_data_files_and_list(pkg); + + err = pkg_run_script(pkg, "postrm", "remove"); + + remove_maintainer_scripts(pkg); + pkg->state_status = SS_NOT_INSTALLED; + + if (parent_pkg) + parent_pkg->state_status = SS_NOT_INSTALLED; + + /* remove autoinstalled packages that are orphaned by the removal of this one */ + if (conf->autoremove) { + if (remove_autoinstalled(pkg) != 0) { + err = -1; + } + } + return err; +} + +void +remove_data_files_and_list(pkg_t *pkg) +{ + str_list_t installed_dirs; + str_list_t *installed_files; + str_list_elt_t *iter; + char *file_name; + conffile_t *conffile; + int removed_a_dir; + pkg_t *owner; + int rootdirlen = 0; + + installed_files = pkg_get_installed_files(pkg); + if (installed_files == NULL) { + opkg_msg(ERROR, "Failed to determine installed " + "files for %s. None removed.\n", pkg->name); + return; + } + + str_list_init(&installed_dirs); + + /* don't include trailing slash */ + if (conf->offline_root) + rootdirlen = strlen(conf->offline_root); + + for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) { + file_name = (char *)iter->data; + + owner = file_hash_get_file_owner(file_name); + if (owner != pkg) + /* File may have been claimed by another package. */ + continue; + + if (file_is_dir(file_name)) { + str_list_append(&installed_dirs, file_name); + continue; + } + + conffile = pkg_get_conffile(pkg, file_name+rootdirlen); + if (conffile) { + if (conffile_has_been_modified(conffile)) { + opkg_msg(NOTICE, "Not deleting modified conffile %s.\n", + file_name); + continue; + } + } + + if (!conf->noaction) { + opkg_msg(INFO, "Deleting %s.\n", file_name); + unlink(file_name); + } else + opkg_msg(INFO, "Not deleting %s. (noaction)\n", + file_name); + + file_hash_remove(file_name); + } + + /* Remove empty directories */ + if (!conf->noaction) { + do { + removed_a_dir = 0; + for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) { + file_name = (char *)iter->data; + + if (rmdir(file_name) == 0) { + opkg_msg(INFO, "Deleting %s.\n", file_name); + removed_a_dir = 1; + str_list_remove(&installed_dirs, &iter); + } + } + } while (removed_a_dir); + } + + pkg_free_installed_files(pkg); + pkg_remove_installed_files_list(pkg); + + /* Don't print warning for dirs that are provided by other packages */ + for (iter = str_list_first(&installed_dirs); iter; iter = str_list_next(&installed_dirs, iter)) { + file_name = (char *)iter->data; + + owner = file_hash_get_file_owner(file_name); + if (owner) { + free(iter->data); + iter->data = NULL; + str_list_remove(&installed_dirs, &iter); + } + } + + /* cleanup */ + while (!void_list_empty(&installed_dirs)) { + iter = str_list_pop(&installed_dirs); + free(iter->data); + free(iter); + } + str_list_deinit(&installed_dirs); +} + +void +remove_maintainer_scripts(pkg_t *pkg) +{ + int i, err; + char *globpattern; + glob_t globbuf; + + if (conf->noaction) + return; + + sprintf_alloc(&globpattern, "%s/%s.*", + pkg->dest->info_dir, pkg->name); + + err = glob(globpattern, 0, NULL, &globbuf); + free(globpattern); + if (err) + return; + + for (i = 0; i < globbuf.gl_pathc; i++) { + opkg_msg(INFO, "Deleting %s.\n", globbuf.gl_pathv[i]); + unlink(globbuf.gl_pathv[i]); + } + globfree(&globbuf); +} diff --git a/src/libopkg/opkg_remove.h b/src/libopkg/opkg_remove.h new file mode 100644 index 0000000..f0c45d2 --- /dev/null +++ b/src/libopkg/opkg_remove.h @@ -0,0 +1,30 @@ +/* opkg_remove.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef OPKG_REMOVE_H +#define OPKG_REMOVE_H + +#include "pkg.h" +#include "opkg_conf.h" + +int opkg_remove_pkg(pkg_t *pkg,int message); +int pkg_has_installed_dependents(pkg_t *pkg, abstract_pkg_t *** pdependents); +void remove_data_files_and_list(pkg_t *pkg); +void remove_maintainer_scripts(pkg_t *pkg); + + +#endif diff --git a/src/libopkg/opkg_upgrade.c b/src/libopkg/opkg_upgrade.c new file mode 100644 index 0000000..10b8217 --- /dev/null +++ b/src/libopkg/opkg_upgrade.c @@ -0,0 +1,130 @@ +/* opkg_upgrade.c - the opkg package management system + + Carl D. Worth + Copyright (C) 2001 University of Southern California + + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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, 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. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#include "opkg_install.h" +#include "opkg_upgrade.h" +#include "opkg_message.h" + +int +opkg_upgrade_pkg(pkg_t *old) +{ + pkg_t *new; + int cmp; + char *old_version, *new_version; + + if (old->state_flag & SF_HOLD) { + opkg_msg(NOTICE, "Not upgrading package %s which is marked " + "hold (flags=%#x).\n", old->name, old->state_flag); + return 0; + } + + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + if (new == NULL) { + old_version = pkg_version_str_alloc(old); + opkg_msg(NOTICE, "Assuming locally installed package %s (%s) " + "is up to date.\n", old->name, old_version); + free(old_version); + return 0; + } + + old_version = pkg_version_str_alloc(old); + new_version = pkg_version_str_alloc(new); + + cmp = pkg_compare_versions(old, new); + opkg_msg(DEBUG, "Comparing visible versions of pkg %s:" + "\n\t%s is installed " + "\n\t%s is available " + "\n\t%d was comparison result\n", + old->name, old_version, new_version, cmp); + if (cmp == 0) { + opkg_msg(INFO, "Package %s (%s) installed in %s is up to date.\n", + old->name, old_version, old->dest->name); + free(old_version); + free(new_version); + return 0; + } else if (cmp > 0) { + opkg_msg(NOTICE, "Not downgrading package %s on %s from %s to %s.\n", + old->name, old->dest->name, old_version, new_version); + free(old_version); + free(new_version); + return 0; + } else if (cmp < 0) { + new->dest = old->dest; + old->state_want = SW_DEINSTALL; + } + + free(old_version); + free(new_version); + new->state_flag |= SF_USER; + return opkg_install_pkg(new,1); +} + + +static void +pkg_hash_check_installed_pkg_helper(const char *pkg_name, void *entry, + void *data) +{ + struct active_list *head = (struct active_list *) data; + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + int j; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (pkg->state_status == SS_INSTALLED + || pkg->state_status == SS_UNPACKED) + active_list_add(head, &pkg->list); + } +} + +struct active_list * +prepare_upgrade_list(void) +{ + struct active_list *head = active_list_head_new(); + struct active_list *all = active_list_head_new(); + struct active_list *node=NULL; + + /* ensure all data is valid */ + pkg_info_preinstall_check(); + + hash_table_foreach(&conf->pkg_hash, pkg_hash_check_installed_pkg_helper, all); + for (node=active_list_next(all,all); node; node = active_list_next(all, node)) { + pkg_t *old, *new; + int cmp; + + old = list_entry(node, pkg_t, list); + new = pkg_hash_fetch_best_installation_candidate_by_name(old->name); + + if (new == NULL) + continue; + + cmp = pkg_compare_versions(old, new); + + if ( cmp < 0 ) { + node = active_list_move_node(all, head, &old->list); + } + } + active_list_head_delete(all); + return head; +} diff --git a/src/libopkg/opkg_upgrade.h b/src/libopkg/opkg_upgrade.h new file mode 100644 index 0000000..6545fa8 --- /dev/null +++ b/src/libopkg/opkg_upgrade.h @@ -0,0 +1,22 @@ +/* opkg_upgrade.c - the opkg package management system + + Copyright (C) 2003 Daniele Nicolodi <daniele@grinta.net> + + 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, 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. +*/ +#ifndef OPKG_UPGRADE_H +#define OPKG_UPGRADE_H + +#include "active_list.h" +int opkg_upgrade_pkg(pkg_t *old); +struct active_list * prepare_upgrade_list (void); + +#endif diff --git a/src/libopkg/opkg_utils.c b/src/libopkg/opkg_utils.c new file mode 100644 index 0000000..ebe4fa8 --- /dev/null +++ b/src/libopkg/opkg_utils.c @@ -0,0 +1,78 @@ +/* opkg_utils.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <ctype.h> +#include <sys/statvfs.h> + +#include "libbb/libbb.h" + +unsigned long +get_available_kbytes(char * filesystem) +{ + struct statvfs f; + + if (statvfs(filesystem, &f) == -1) { + opkg_perror(ERROR, "Failed to statvfs for %s", filesystem); + return 0; + } + + // Actually ((sfs.f_bavail * sfs.f_frsize) / 1024) + // and here we try to avoid overflow. + if (f.f_frsize >= 1024) + return (f.f_bavail * (f.f_frsize / 1024)); + else if (f.f_frsize > 0) + return f.f_bavail / (1024 / f.f_frsize); + + opkg_msg(ERROR, "Unknown block size for target filesystem.\n"); + + return 0; +} + +/* something to remove whitespace, a hash pooper */ +char *trim_xstrdup(const char *src) +{ + const char *end; + + /* remove it from the front */ + while(src && + isspace(*src) && + *src) + src++; + + end = src + (strlen(src) - 1); + + /* and now from the back */ + while((end > src) && + isspace(*end)) + end--; + + end++; + + /* xstrndup will NULL terminate for us */ + return xstrndup(src, end-src); +} + +int line_is_blank(const char *line) +{ + const char *s; + + for (s = line; *s; s++) { + if (!isspace(*s)) + return 0; + } + return 1; +} diff --git a/src/libopkg/opkg_utils.h b/src/libopkg/opkg_utils.h new file mode 100644 index 0000000..092d158 --- /dev/null +++ b/src/libopkg/opkg_utils.h @@ -0,0 +1,25 @@ +/* opkg_utils.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef OPKG_UTILS_H +#define OPKG_UTILS_H + +unsigned long get_available_kbytes(char * filesystem); +char *trim_xstrdup(const char *line); +int line_is_blank(const char *line); + +#endif diff --git a/src/libopkg/parse_util.c b/src/libopkg/parse_util.c new file mode 100644 index 0000000..54850a8 --- /dev/null +++ b/src/libopkg/parse_util.c @@ -0,0 +1,168 @@ +/* parse_util.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Steven M. Ayer + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <ctype.h> + +#include "opkg_utils.h" +#include "libbb/libbb.h" + +#include "parse_util.h" + +int +is_field(const char *type, const char *line) +{ + if (!strncmp(line, type, strlen(type))) + return 1; + return 0; +} + +char * +parse_simple(const char *type, const char *line) +{ + return trim_xstrdup(line + strlen(type) + 1); +} + +/* + * Parse a comma separated string into an array. + */ +char ** +parse_list(const char *raw, unsigned int *count, const char sep, int skip_field) +{ + char **depends = NULL; + const char *start, *end; + int line_count = 0; + + /* skip past the "Field:" marker */ + if (!skip_field) { + while (*raw && *raw != ':') + raw++; + raw++; + } + + if (line_is_blank(raw)) { + *count = line_count; + return NULL; + } + + while (*raw) { + depends = xrealloc(depends, sizeof(char *) * (line_count + 1)); + + while (isspace(*raw)) + raw++; + + start = raw; + while (*raw != sep && *raw) + raw++; + end = raw; + + while (end > start && isspace(*end)) + end--; + + if (sep == ' ') + end++; + + depends[line_count] = xstrndup(start, end-start); + + line_count++; + if (*raw == sep) + raw++; + } + + *count = line_count; + return depends; +} + +int +parse_from_stream_nomalloc(parse_line_t parse_line, void *ptr, FILE *fp, uint mask, + char **buf0, size_t buf0len) +{ + int ret, lineno; + char *buf, *nl; + size_t buflen; + + lineno = 1; + ret = 0; + + buflen = buf0len; + buf = *buf0; + buf[0] = '\0'; + + while (1) { + if (fgets(buf, (int)buflen, fp) == NULL) { + if (ferror(fp)) { + opkg_perror(ERROR, "fgets"); + ret = -1; + } else if (strlen(*buf0) == buf0len-1) { + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(ptr, *buf0, mask); + } + break; + } + + nl = strchr(buf, '\n'); + if (nl == NULL) { + if (strlen(buf) < buflen-1) { + /* + * Line could be exactly buflen-1 long and + * missing a newline, but we won't know until + * fgets fails to read more data. + */ + opkg_msg(ERROR, "Missing new line character" + " at end of file!\n"); + parse_line(ptr, *buf0, mask); + break; + } + if (buf0len >= EXCESSIVE_LINE_LEN) { + opkg_msg(ERROR, "Excessively long line at " + "%d. Corrupt file?\n", + lineno); + ret = -1; + break; + } + + /* + * Realloc and point buf past the data already read, + * at the NULL terminator inserted by fgets. + * |<--------------- buf0len ----------------->| + * | |<------- buflen ---->| + * |---------------------|---------------------| + * buf0 buf + */ + buflen = buf0len +1; + buf0len *= 2; + *buf0 = xrealloc(*buf0, buf0len); + buf = *buf0 + buflen -2; + + continue; + } + + *nl = '\0'; + + lineno++; + + if (parse_line(ptr, *buf0, mask)) + break; + + buf = *buf0; + buflen = buf0len; + buf[0] = '\0'; + } + + return ret; +} diff --git a/src/libopkg/parse_util.h b/src/libopkg/parse_util.h new file mode 100644 index 0000000..26e2d5b --- /dev/null +++ b/src/libopkg/parse_util.h @@ -0,0 +1,31 @@ +/* parse_util.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PARSE_UTIL_H +#define PARSE_UTIL_H + +int is_field(const char *type, const char *line); +char *parse_simple(const char *type, const char *line); +char **parse_list(const char *raw, unsigned int *count, const char sep, int skip_field); + +typedef int (*parse_line_t)(void *, const char *, uint); +int parse_from_stream_nomalloc(parse_line_t parse_line, void *item, FILE *fp, uint mask, + char **buf0, size_t buf0len); + +#define EXCESSIVE_LINE_LEN (4096 << 8) + +#endif diff --git a/src/libopkg/pkg.c b/src/libopkg/pkg.c new file mode 100644 index 0000000..d8c3984 --- /dev/null +++ b/src/libopkg/pkg.c @@ -0,0 +1,1428 @@ +/* pkg.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <libgen.h> + +#include "pkg.h" + +#include "pkg_parse.h" +#include "pkg_extract.h" +#include "opkg_message.h" +#include "opkg_utils.h" + +#include "libbb/libbb.h" +#include "sprintf_alloc.h" +#include "file_util.h" +#include "xsystem.h" +#include "opkg_conf.h" + +typedef struct enum_map enum_map_t; +struct enum_map +{ + unsigned int value; + const char *str; +}; + +static const enum_map_t pkg_state_want_map[] = { + { SW_UNKNOWN, "unknown"}, + { SW_INSTALL, "install"}, + { SW_DEINSTALL, "deinstall"}, + { SW_PURGE, "purge"} +}; + +static const enum_map_t pkg_state_flag_map[] = { + { SF_OK, "ok"}, + { SF_REINSTREQ, "reinstreq"}, + { SF_HOLD, "hold"}, + { SF_REPLACE, "replace"}, + { SF_NOPRUNE, "noprune"}, + { SF_PREFER, "prefer"}, + { SF_OBSOLETE, "obsolete"}, + { SF_USER, "user"}, +}; + +static const enum_map_t pkg_state_status_map[] = { + { SS_NOT_INSTALLED, "not-installed" }, + { SS_UNPACKED, "unpacked" }, + { SS_HALF_CONFIGURED, "half-configured" }, + { SS_INSTALLED, "installed" }, + { SS_HALF_INSTALLED, "half-installed" }, + { SS_CONFIG_FILES, "config-files" }, + { SS_POST_INST_FAILED, "post-inst-failed" }, + { SS_REMOVAL_FAILED, "removal-failed" } +}; + +static void +pkg_init(pkg_t *pkg) +{ + pkg->name = NULL; + pkg->epoch = 0; + pkg->version = NULL; + pkg->revision = NULL; + pkg->dest = NULL; + pkg->src = NULL; + pkg->architecture = NULL; + pkg->maintainer = NULL; + pkg->section = NULL; + pkg->description = NULL; + pkg->state_want = SW_UNKNOWN; + pkg->state_flag = SF_OK; + pkg->state_status = SS_NOT_INSTALLED; + pkg->depends_str = NULL; + pkg->provides_str = NULL; + pkg->depends_count = 0; + pkg->depends = NULL; + pkg->suggests_str = NULL; + pkg->recommends_str = NULL; + pkg->suggests_count = 0; + pkg->recommends_count = 0; + + active_list_init(&pkg->list); + + pkg->conflicts = NULL; + pkg->conflicts_count = 0; + + pkg->replaces = NULL; + pkg->replaces_count = 0; + + pkg->pre_depends_count = 0; + pkg->pre_depends_str = NULL; + pkg->provides_count = 0; + pkg->provides = NULL; + pkg->filename = NULL; + pkg->local_filename = NULL; + pkg->tmp_unpack_dir = NULL; + pkg->md5sum = NULL; +#if defined HAVE_SHA256 + pkg->sha256sum = NULL; +#endif + pkg->size = 0; + pkg->installed_size = 0; + pkg->priority = NULL; + pkg->source = NULL; + conffile_list_init(&pkg->conffiles); + pkg->installed_files = NULL; + pkg->installed_files_ref_cnt = 0; + pkg->essential = 0; + pkg->provided_by_hand = 0; +} + +pkg_t * +pkg_new(void) +{ + pkg_t *pkg; + + pkg = xcalloc(1, sizeof(pkg_t)); + pkg_init(pkg); + + return pkg; +} + +static void +compound_depend_deinit(compound_depend_t *depends) +{ + int i; + for (i = 0; i < depends->possibility_count; i++) + { + depend_t *d; + d = depends->possibilities[i]; + free (d->version); + free (d); + } + free (depends->possibilities); +} + +void +pkg_deinit(pkg_t *pkg) +{ + int i; + + if (pkg->name) + free(pkg->name); + pkg->name = NULL; + + pkg->epoch = 0; + + if (pkg->version) + free(pkg->version); + pkg->version = NULL; + /* revision shares storage with version, so don't free */ + pkg->revision = NULL; + + /* owned by opkg_conf_t */ + pkg->dest = NULL; + /* owned by opkg_conf_t */ + pkg->src = NULL; + + if (pkg->architecture) + free(pkg->architecture); + pkg->architecture = NULL; + + if (pkg->maintainer) + free(pkg->maintainer); + pkg->maintainer = NULL; + + if (pkg->section) + free(pkg->section); + pkg->section = NULL; + + if (pkg->description) + free(pkg->description); + pkg->description = NULL; + + pkg->state_want = SW_UNKNOWN; + pkg->state_flag = SF_OK; + pkg->state_status = SS_NOT_INSTALLED; + + active_list_clear(&pkg->list); + + if (pkg->replaces) + free (pkg->replaces); + pkg->replaces = NULL; + + if (pkg->depends) { + int count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i=0; i<count; i++) + compound_depend_deinit (&pkg->depends[i]); + free (pkg->depends); + } + + if (pkg->conflicts) { + for (i=0; i<pkg->conflicts_count; i++) + compound_depend_deinit (&pkg->conflicts[i]); + free (pkg->conflicts); + } + + if (pkg->provides) + free (pkg->provides); + + pkg->pre_depends_count = 0; + pkg->provides_count = 0; + + if (pkg->filename) + free(pkg->filename); + pkg->filename = NULL; + + if (pkg->local_filename) + free(pkg->local_filename); + pkg->local_filename = NULL; + + /* CLEANUP: It'd be nice to pullin the cleanup function from + opkg_install.c here. See comment in + opkg_install.c:cleanup_temporary_files */ + if (pkg->tmp_unpack_dir) + free(pkg->tmp_unpack_dir); + pkg->tmp_unpack_dir = NULL; + + if (pkg->md5sum) + free(pkg->md5sum); + pkg->md5sum = NULL; + +#if defined HAVE_SHA256 + if (pkg->sha256sum) + free(pkg->sha256sum); + pkg->sha256sum = NULL; +#endif + + if (pkg->priority) + free(pkg->priority); + pkg->priority = NULL; + + if (pkg->source) + free(pkg->source); + pkg->source = NULL; + + conffile_list_deinit(&pkg->conffiles); + + /* XXX: QUESTION: Is forcing this to 1 correct? I suppose so, + since if they are calling deinit, they should know. Maybe do an + assertion here instead? */ + pkg->installed_files_ref_cnt = 1; + pkg_free_installed_files(pkg); + pkg->essential = 0; + + if (pkg->tags) + free (pkg->tags); + pkg->tags = NULL; +} + +int +pkg_init_from_file(pkg_t *pkg, const char *filename) +{ + int fd, err = 0; + FILE *control_file; + char *control_path, *tmp; + + pkg_init(pkg); + + pkg->local_filename = xstrdup(filename); + + tmp = xstrdup(filename); + sprintf_alloc(&control_path, "%s/%s.control.XXXXXX", + conf->tmp_dir, + basename(tmp)); + free(tmp); + fd = mkstemp(control_path); + if (fd == -1) { + opkg_perror(ERROR, "Failed to make temp file %s", control_path); + err = -1; + goto err0; + } + + control_file = fdopen(fd, "r+"); + if (control_file == NULL) { + opkg_perror(ERROR, "Failed to fdopen %s", control_path); + close(fd); + err = -1; + goto err1; + } + + err = pkg_extract_control_file_to_stream(pkg, control_file); + if (err) { + opkg_msg(ERROR, "Failed to extract control file from %s.\n", + filename); + goto err2; + } + + rewind(control_file); + + if ((err = pkg_parse_from_stream(pkg, control_file, 0))) { + if (err == 1) { + opkg_msg(ERROR, "Malformed package file %s.\n", + filename); + } + err = -1; + } + +err2: + fclose(control_file); +err1: + unlink(control_path); +err0: + free(control_path); + + return err; +} + +/* Merge any new information in newpkg into oldpkg */ +int +pkg_merge(pkg_t *oldpkg, pkg_t *newpkg) +{ + if (oldpkg == newpkg) { + return 0; + } + + if (!oldpkg->auto_installed) + oldpkg->auto_installed = newpkg->auto_installed; + + if (!oldpkg->src) + oldpkg->src = newpkg->src; + if (!oldpkg->dest) + oldpkg->dest = newpkg->dest; + if (!oldpkg->architecture) + oldpkg->architecture = xstrdup(newpkg->architecture); + if (!oldpkg->arch_priority) + oldpkg->arch_priority = newpkg->arch_priority; + if (!oldpkg->section) + oldpkg->section = xstrdup(newpkg->section); + if(!oldpkg->maintainer) + oldpkg->maintainer = xstrdup(newpkg->maintainer); + if(!oldpkg->description) + oldpkg->description = xstrdup(newpkg->description); + + if (!oldpkg->depends_count && !oldpkg->pre_depends_count && !oldpkg->recommends_count && !oldpkg->suggests_count) { + oldpkg->depends_count = newpkg->depends_count; + newpkg->depends_count = 0; + + oldpkg->depends = newpkg->depends; + newpkg->depends = NULL; + + oldpkg->pre_depends_count = newpkg->pre_depends_count; + newpkg->pre_depends_count = 0; + + oldpkg->recommends_count = newpkg->recommends_count; + newpkg->recommends_count = 0; + + oldpkg->suggests_count = newpkg->suggests_count; + newpkg->suggests_count = 0; + } + + if (oldpkg->provides_count <= 1) { + oldpkg->provides_count = newpkg->provides_count; + newpkg->provides_count = 0; + + if (!oldpkg->provides) { + oldpkg->provides = newpkg->provides; + newpkg->provides = NULL; + } + } + + if (!oldpkg->conflicts_count) { + oldpkg->conflicts_count = newpkg->conflicts_count; + newpkg->conflicts_count = 0; + + oldpkg->conflicts = newpkg->conflicts; + newpkg->conflicts = NULL; + } + + if (!oldpkg->replaces_count) { + oldpkg->replaces_count = newpkg->replaces_count; + newpkg->replaces_count = 0; + + oldpkg->replaces = newpkg->replaces; + newpkg->replaces = NULL; + } + + if (!oldpkg->filename) + oldpkg->filename = xstrdup(newpkg->filename); + if (!oldpkg->local_filename) + oldpkg->local_filename = xstrdup(newpkg->local_filename); + if (!oldpkg->tmp_unpack_dir) + oldpkg->tmp_unpack_dir = xstrdup(newpkg->tmp_unpack_dir); + if (!oldpkg->md5sum) + oldpkg->md5sum = xstrdup(newpkg->md5sum); +#if defined HAVE_SHA256 + if (!oldpkg->sha256sum) + oldpkg->sha256sum = xstrdup(newpkg->sha256sum); +#endif + if (!oldpkg->size) + oldpkg->size = newpkg->size; + if (!oldpkg->installed_size) + oldpkg->installed_size = newpkg->installed_size; + if (!oldpkg->priority) + oldpkg->priority = xstrdup(newpkg->priority); + if (!oldpkg->source) + oldpkg->source = xstrdup(newpkg->source); + + if (nv_pair_list_empty(&oldpkg->conffiles)){ + list_splice_init(&newpkg->conffiles.head, &oldpkg->conffiles.head); + } + + if (!oldpkg->installed_files){ + oldpkg->installed_files = newpkg->installed_files; + oldpkg->installed_files_ref_cnt = newpkg->installed_files_ref_cnt; + newpkg->installed_files = NULL; + } + + if (!oldpkg->essential) + oldpkg->essential = newpkg->essential; + + return 0; +} + +static void +abstract_pkg_init(abstract_pkg_t *ab_pkg) +{ + ab_pkg->provided_by = abstract_pkg_vec_alloc(); + ab_pkg->dependencies_checked = 0; + ab_pkg->state_status = SS_NOT_INSTALLED; +} + +abstract_pkg_t * +abstract_pkg_new(void) +{ + abstract_pkg_t * ab_pkg; + + ab_pkg = xcalloc(1, sizeof(abstract_pkg_t)); + abstract_pkg_init(ab_pkg); + + return ab_pkg; +} + +void +set_flags_from_control(pkg_t *pkg){ + char *file_name; + FILE *fp; + + sprintf_alloc(&file_name,"%s/%s.control", pkg->dest->info_dir, pkg->name); + + fp = fopen(file_name, "r"); + if (fp == NULL) { + opkg_perror(ERROR, "Failed to open %s", file_name); + free(file_name); + return; + } + + free(file_name); + + if (pkg_parse_from_stream(pkg, fp, PFM_ALL ^ PFM_ESSENTIAL)) { + opkg_msg(DEBUG, "Unable to read control file for %s. May be empty.\n", + pkg->name); + } + + fclose(fp); + + return; +} + +static const char * +pkg_state_want_to_str(pkg_state_want_t sw) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) { + if (pkg_state_want_map[i].value == sw) { + return pkg_state_want_map[i].str; + } + } + + opkg_msg(ERROR, "Internal error: state_want=%d\n", sw); + return "<STATE_WANT_UNKNOWN>"; +} + +pkg_state_want_t +pkg_state_want_from_str(char *str) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_want_map); i++) { + if (strcmp(str, pkg_state_want_map[i].str) == 0) { + return pkg_state_want_map[i].value; + } + } + + opkg_msg(ERROR, "Internal error: state_want=%s\n", str); + return SW_UNKNOWN; +} + +static char * +pkg_state_flag_to_str(pkg_state_flag_t sf) +{ + int i; + unsigned int len; + char *str; + + /* clear the temporary flags before converting to string */ + sf &= SF_NONVOLATILE_FLAGS; + + if (sf == 0) + return xstrdup("ok"); + + len = 0; + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + if (sf & pkg_state_flag_map[i].value) + len += strlen(pkg_state_flag_map[i].str) + 1; + } + + str = xmalloc(len+1); + str[0] = '\0'; + + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + if (sf & pkg_state_flag_map[i].value) { + strncat(str, pkg_state_flag_map[i].str, len); + strncat(str, ",", len); + } + } + + len = strlen(str); + str[len-1] = '\0'; /* squash last comma */ + + return str; +} + +pkg_state_flag_t +pkg_state_flag_from_str(const char *str) +{ + int i; + int sf = SF_OK; + const char *sfname; + unsigned int sfname_len; + + if (strcmp(str, "ok") == 0) { + return SF_OK; + } + for (i=0; i < ARRAY_SIZE(pkg_state_flag_map); i++) { + sfname = pkg_state_flag_map[i].str; + sfname_len = strlen(sfname); + if (strncmp(str, sfname, sfname_len) == 0) { + sf |= pkg_state_flag_map[i].value; + str += sfname_len; + if (str[0] == ',') { + str++; + } else { + break; + } + } + } + + return sf; +} + +static const char * +pkg_state_status_to_str(pkg_state_status_t ss) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) { + if (pkg_state_status_map[i].value == ss) { + return pkg_state_status_map[i].str; + } + } + + opkg_msg(ERROR, "Internal error: state_status=%d\n", ss); + return "<STATE_STATUS_UNKNOWN>"; +} + +pkg_state_status_t +pkg_state_status_from_str(const char *str) +{ + int i; + + for (i=0; i < ARRAY_SIZE(pkg_state_status_map); i++) { + if (strcmp(str, pkg_state_status_map[i].str) == 0) { + return pkg_state_status_map[i].value; + } + } + + opkg_msg(ERROR, "Internal error: state_status=%s\n", str); + return SS_NOT_INSTALLED; +} + +void +pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field) +{ + int i, j; + char *str; + int depends_count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + if (strlen(field) < PKG_MINIMUM_FIELD_NAME_LEN) { + goto UNKNOWN_FMT_FIELD; + } + + switch (field[0]) + { + case 'a': + case 'A': + if (strcasecmp(field, "Architecture") == 0) { + if (pkg->architecture) { + fprintf(fp, "Architecture: %s\n", pkg->architecture); + } + } else if (strcasecmp(field, "Auto-Installed") == 0) { + if (pkg->auto_installed) + fprintf(fp, "Auto-Installed: yes\n"); + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'c': + case 'C': + if (strcasecmp(field, "Conffiles") == 0) { + conffile_list_elt_t *iter; + + if (nv_pair_list_empty(&pkg->conffiles)) + return; + + fprintf(fp, "Conffiles:\n"); + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + if (((conffile_t *)iter->data)->name && ((conffile_t *)iter->data)->value) { + fprintf(fp, " %s %s\n", + ((conffile_t *)iter->data)->name, + ((conffile_t *)iter->data)->value); + } + } + } else if (strcasecmp(field, "Conflicts") == 0) { + struct depend *cdep; + if (pkg->conflicts_count) { + fprintf(fp, "Conflicts:"); + for(i = 0; i < pkg->conflicts_count; i++) { + cdep = pkg->conflicts[i].possibilities[0]; + fprintf(fp, "%s %s", i == 0 ? "" : ",", + cdep->pkg->name); + if (cdep->version) { + fprintf(fp, " (%s%s)", + constraint_to_str(cdep->constraint), + cdep->version); + } + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'd': + case 'D': + if (strcasecmp(field, "Depends") == 0) { + if (pkg->depends_count) { + fprintf(fp, "Depends:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != DEPEND) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else if (strcasecmp(field, "Description") == 0) { + if (pkg->description) { + fprintf(fp, "Description: %s\n", pkg->description); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'e': + case 'E': + if (pkg->essential) { + fprintf(fp, "Essential: yes\n"); + } + break; + case 'f': + case 'F': + if (pkg->filename) { + fprintf(fp, "Filename: %s\n", pkg->filename); + } + break; + case 'i': + case 'I': + if (strcasecmp(field, "Installed-Size") == 0) { + fprintf(fp, "Installed-Size: %ld\n", pkg->installed_size); + } else if (strcasecmp(field, "Installed-Time") == 0 && pkg->installed_time) { + fprintf(fp, "Installed-Time: %lu\n", pkg->installed_time); + } + break; + case 'm': + case 'M': + if (strcasecmp(field, "Maintainer") == 0) { + if (pkg->maintainer) { + fprintf(fp, "Maintainer: %s\n", pkg->maintainer); + } + } else if (strcasecmp(field, "MD5sum") == 0) { + if (pkg->md5sum) { + fprintf(fp, "MD5Sum: %s\n", pkg->md5sum); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'p': + case 'P': + if (strcasecmp(field, "Package") == 0) { + fprintf(fp, "Package: %s\n", pkg->name); + } else if (strcasecmp(field, "Priority") == 0) { + fprintf(fp, "Priority: %s\n", pkg->priority); + } else if (strcasecmp(field, "Provides") == 0) { + if (pkg->provides_count) { + fprintf(fp, "Provides:"); + for(i = 1; i < pkg->provides_count; i++) { + fprintf(fp, "%s %s", i == 1 ? "" : ",", + pkg->provides[i]->name); + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 'r': + case 'R': + if (strcasecmp (field, "Replaces") == 0) { + if (pkg->replaces_count) { + fprintf(fp, "Replaces:"); + for (i = 0; i < pkg->replaces_count; i++) { + fprintf(fp, "%s %s", i == 0 ? "" : ",", + pkg->replaces[i]->name); + } + fprintf(fp, "\n"); + } + } else if (strcasecmp (field, "Recommends") == 0) { + if (pkg->recommends_count) { + fprintf(fp, "Recommends:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != RECOMMEND) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 's': + case 'S': + if (strcasecmp(field, "Section") == 0) { + if (pkg->section) { + fprintf(fp, "Section: %s\n", pkg->section); + } +#if defined HAVE_SHA256 + } else if (strcasecmp(field, "SHA256sum") == 0) { + if (pkg->sha256sum) { + fprintf(fp, "SHA256sum: %s\n", pkg->sha256sum); + } +#endif + } else if (strcasecmp(field, "Size") == 0) { + if (pkg->size) { + fprintf(fp, "Size: %ld\n", pkg->size); + } + } else if (strcasecmp(field, "Source") == 0) { + if (pkg->source) { + fprintf(fp, "Source: %s\n", pkg->source); + } + } else if (strcasecmp(field, "Status") == 0) { + char *pflag = pkg_state_flag_to_str(pkg->state_flag); + fprintf(fp, "Status: %s %s %s\n", + pkg_state_want_to_str(pkg->state_want), + pflag, + pkg_state_status_to_str(pkg->state_status)); + free(pflag); + } else if (strcasecmp(field, "Suggests") == 0) { + if (pkg->suggests_count) { + fprintf(fp, "Suggests:"); + for (j=0, i=0; i<depends_count; i++) { + if (pkg->depends[i].type != SUGGEST) + continue; + str = pkg_depend_str(pkg, i); + fprintf(fp, "%s %s", j == 0 ? "" : ",", str); + free(str); + j++; + } + fprintf(fp, "\n"); + } + } else { + goto UNKNOWN_FMT_FIELD; + } + break; + case 't': + case 'T': + if (strcasecmp(field, "Tags") == 0) { + if (pkg->tags) { + fprintf(fp, "Tags: %s\n", pkg->tags); + } + } + break; + case 'v': + case 'V': + { + char *version = pkg_version_str_alloc(pkg); + if (version == NULL) + return; + fprintf(fp, "Version: %s\n", version); + free(version); + } + break; + default: + goto UNKNOWN_FMT_FIELD; + } + + return; + +UNKNOWN_FMT_FIELD: + opkg_msg(ERROR, "Internal error: field=%s\n", field); +} + +void +pkg_formatted_info(FILE *fp, pkg_t *pkg) +{ + pkg_formatted_field(fp, pkg, "Package"); + pkg_formatted_field(fp, pkg, "Version"); + pkg_formatted_field(fp, pkg, "Depends"); + pkg_formatted_field(fp, pkg, "Recommends"); + pkg_formatted_field(fp, pkg, "Suggests"); + pkg_formatted_field(fp, pkg, "Provides"); + pkg_formatted_field(fp, pkg, "Replaces"); + pkg_formatted_field(fp, pkg, "Conflicts"); + pkg_formatted_field(fp, pkg, "Status"); + pkg_formatted_field(fp, pkg, "Section"); + pkg_formatted_field(fp, pkg, "Essential"); + pkg_formatted_field(fp, pkg, "Architecture"); + pkg_formatted_field(fp, pkg, "Maintainer"); + pkg_formatted_field(fp, pkg, "MD5sum"); + pkg_formatted_field(fp, pkg, "Size"); + pkg_formatted_field(fp, pkg, "Filename"); + pkg_formatted_field(fp, pkg, "Conffiles"); + pkg_formatted_field(fp, pkg, "Source"); + pkg_formatted_field(fp, pkg, "Description"); + pkg_formatted_field(fp, pkg, "Installed-Time"); + pkg_formatted_field(fp, pkg, "Tags"); + fputs("\n", fp); +} + +void +pkg_print_status(pkg_t * pkg, FILE * file) +{ + if (pkg == NULL) { + return; + } + + pkg_formatted_field(file, pkg, "Package"); + pkg_formatted_field(file, pkg, "Version"); + pkg_formatted_field(file, pkg, "Depends"); + pkg_formatted_field(file, pkg, "Recommends"); + pkg_formatted_field(file, pkg, "Suggests"); + pkg_formatted_field(file, pkg, "Provides"); + pkg_formatted_field(file, pkg, "Replaces"); + pkg_formatted_field(file, pkg, "Conflicts"); + pkg_formatted_field(file, pkg, "Status"); + pkg_formatted_field(file, pkg, "Essential"); + pkg_formatted_field(file, pkg, "Architecture"); + pkg_formatted_field(file, pkg, "Conffiles"); + pkg_formatted_field(file, pkg, "Installed-Time"); + pkg_formatted_field(file, pkg, "Auto-Installed"); + fputs("\n", file); +} + +/* + * libdpkg - Debian packaging suite library routines + * vercmp.c - comparison of version numbers + * + * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk> + */ + +/* assume ascii; warning: evaluates x multiple times! */ +#define order(x) ((x) == '~' ? -1 \ + : isdigit((x)) ? 0 \ + : !(x) ? 0 \ + : isalpha((x)) ? (x) \ + : (x) + 256) + +static int +verrevcmp(const char *val, const char *ref) { + if (!val) val= ""; + if (!ref) ref= ""; + + while (*val || *ref) { + int first_diff= 0; + + while ( (*val && !isdigit(*val)) || (*ref && !isdigit(*ref)) ) { + int vc= order(*val), rc= order(*ref); + if (vc != rc) return vc - rc; + val++; ref++; + } + + while ( *val == '0' ) val++; + while ( *ref == '0' ) ref++; + while (isdigit(*val) && isdigit(*ref)) { + if (!first_diff) first_diff= *val - *ref; + val++; ref++; + } + if (isdigit(*val)) return 1; + if (isdigit(*ref)) return -1; + if (first_diff) return first_diff; + } + return 0; +} + +int +pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg) +{ + int r; + + if (pkg->epoch > ref_pkg->epoch) { + return 1; + } + + if (pkg->epoch < ref_pkg->epoch) { + return -1; + } + + r = verrevcmp(pkg->version, ref_pkg->version); + if (r) { + return r; + } + + r = verrevcmp(pkg->revision, ref_pkg->revision); + if (r) { + return r; + } + + return r; +} + + +int +pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op) +{ + int r; + + r = pkg_compare_versions(it, ref); + + if (strcmp(op, "<=") == 0 || strcmp(op, "<") == 0) { + return r <= 0; + } + + if (strcmp(op, ">=") == 0 || strcmp(op, ">") == 0) { + return r >= 0; + } + + if (strcmp(op, "<<") == 0) { + return r < 0; + } + + if (strcmp(op, ">>") == 0) { + return r > 0; + } + + if (strcmp(op, "=") == 0) { + return r == 0; + } + + opkg_msg(ERROR, "Unknown operator: %s.\n", op); + return 0; +} + +int +pkg_name_version_and_architecture_compare(const void *p1, const void *p2) +{ + const pkg_t *a = *(const pkg_t**) p1; + const pkg_t *b = *(const pkg_t**) p2; + int namecmp; + int vercmp; + if (!a->name || !b->name) { + opkg_msg(ERROR, "Internal error: a->name=%p, b->name=%p.\n", + a->name, b->name); + return 0; + } + + namecmp = strcmp(a->name, b->name); + if (namecmp) + return namecmp; + vercmp = pkg_compare_versions(a, b); + if (vercmp) + return vercmp; + if (!a->arch_priority || !b->arch_priority) { + opkg_msg(ERROR, "Internal error: a->arch_priority=%i b->arch_priority=%i.\n", + a->arch_priority, b->arch_priority); + return 0; + } + if (a->arch_priority > b->arch_priority) + return 1; + if (a->arch_priority < b->arch_priority) + return -1; + return 0; +} + +int +abstract_pkg_name_compare(const void *p1, const void *p2) +{ + const abstract_pkg_t *a = *(const abstract_pkg_t **)p1; + const abstract_pkg_t *b = *(const abstract_pkg_t **)p2; + if (!a->name || !b->name) { + opkg_msg(ERROR, "Internal error: a->name=%p b->name=%p.\n", + a->name, b->name); + return 0; + } + return strcmp(a->name, b->name); +} + + +char * +pkg_version_str_alloc(pkg_t *pkg) +{ + char *version; + + if (pkg->epoch) { + if (pkg->revision) + sprintf_alloc(&version, "%d:%s-%s", + pkg->epoch, pkg->version, pkg->revision); + else + sprintf_alloc(&version, "%d:%s", + pkg->epoch, pkg->version); + } else { + if (pkg->revision) + sprintf_alloc(&version, "%s-%s", + pkg->version, pkg->revision); + else + version = xstrdup(pkg->version); + } + + return version; +} + +/* + * XXX: this should be broken into two functions + */ +str_list_t * +pkg_get_installed_files(pkg_t *pkg) +{ + int err, fd; + char *list_file_name = NULL; + FILE *list_file = NULL; + char *line; + char *installed_file_name; + unsigned int rootdirlen = 0; + int list_from_package; + + pkg->installed_files_ref_cnt++; + + if (pkg->installed_files) { + return pkg->installed_files; + } + + pkg->installed_files = str_list_alloc(); + + /* + * For installed packages, look at the package.list file in the database. + * For uninstalled packages, get the file list directly from the package. + */ + if (pkg->state_status == SS_NOT_INSTALLED || pkg->dest == NULL) + list_from_package = 1; + else + list_from_package = 0; + + if (list_from_package) { + if (pkg->local_filename == NULL) { + return pkg->installed_files; + } + /* XXX: CLEANUP: Maybe rewrite this to avoid using a temporary + file. In other words, change deb_extract so that it can + simply return the file list as a char *[] rather than + insisting on writing it to a FILE * as it does now. */ + sprintf_alloc(&list_file_name, "%s/%s.list.XXXXXX", + conf->tmp_dir, pkg->name); + fd = mkstemp(list_file_name); + if (fd == -1) { + opkg_perror(ERROR, "Failed to make temp file %s.", + list_file_name); + free(list_file_name); + return pkg->installed_files; + } + list_file = fdopen(fd, "r+"); + if (list_file == NULL) { + opkg_perror(ERROR, "Failed to fdopen temp file %s.", + list_file_name); + close(fd); + unlink(list_file_name); + free(list_file_name); + return pkg->installed_files; + } + err = pkg_extract_data_file_names_to_stream(pkg, list_file); + if (err) { + opkg_msg(ERROR, "Error extracting file list from %s.\n", + pkg->local_filename); + fclose(list_file); + unlink(list_file_name); + free(list_file_name); + str_list_deinit(pkg->installed_files); + pkg->installed_files = NULL; + return NULL; + } + rewind(list_file); + } else { + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + list_file = fopen(list_file_name, "r"); + if (list_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", + list_file_name); + free(list_file_name); + return pkg->installed_files; + } + free(list_file_name); + } + + if (conf->offline_root) + rootdirlen = strlen(conf->offline_root); + + while (1) { + char *file_name; + + line = file_read_line_alloc(list_file); + if (line == NULL) { + break; + } + file_name = line; + + if (list_from_package) { + if (*file_name == '.') { + file_name++; + } + if (*file_name == '/') { + file_name++; + } + sprintf_alloc(&installed_file_name, "%s%s", + pkg->dest->root_dir, file_name); + } else { + if (conf->offline_root && + strncmp(conf->offline_root, file_name, rootdirlen)) { + sprintf_alloc(&installed_file_name, "%s%s", + conf->offline_root, file_name); + } else { + // already contains root_dir as header -> ABSOLUTE + sprintf_alloc(&installed_file_name, "%s", file_name); + } + } + str_list_append(pkg->installed_files, installed_file_name); + free(installed_file_name); + free(line); + } + + fclose(list_file); + + if (list_from_package) { + unlink(list_file_name); + free(list_file_name); + } + + return pkg->installed_files; +} + +/* XXX: CLEANUP: This function and it's counterpart, + (pkg_get_installed_files), do not match our init/deinit naming + convention. Nor the alloc/free convention. But, then again, neither + of these conventions currrently fit the way these two functions + work. */ +void +pkg_free_installed_files(pkg_t *pkg) +{ + pkg->installed_files_ref_cnt--; + + if (pkg->installed_files_ref_cnt > 0) + return; + + if (pkg->installed_files) { + str_list_purge(pkg->installed_files); + } + + pkg->installed_files = NULL; +} + +void +pkg_remove_installed_files_list(pkg_t *pkg) +{ + char *list_file_name; + + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + + if (!conf->noaction) + (void)unlink(list_file_name); + + free(list_file_name); +} + +conffile_t * +pkg_get_conffile(pkg_t *pkg, const char *file_name) +{ + conffile_list_elt_t *iter; + conffile_t *conffile; + + if (pkg == NULL) { + return NULL; + } + + for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) { + conffile = (conffile_t *)iter->data; + + if (strcmp(conffile->name, file_name) == 0) { + return conffile; + } + } + + return NULL; +} + +int +pkg_run_script(pkg_t *pkg, const char *script, const char *args) +{ + int err; + char *path; + char *cmd; + + if (conf->noaction) + return 0; + + if (conf->offline_root && !conf->force_postinstall) { + opkg_msg(INFO, "Offline root mode: not running %s.%s.\n", + pkg->name, script); + return 0; + } + + /* Installed packages have scripts in pkg->dest->info_dir, uninstalled packages + have scripts in pkg->tmp_unpack_dir. */ + if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) { + if (pkg->dest == NULL) { + opkg_msg(ERROR, "Internal error: %s has a NULL dest.\n", + pkg->name); + return -1; + } + sprintf_alloc(&path, "%s/%s.%s", pkg->dest->info_dir, pkg->name, script); + } else { + if (pkg->tmp_unpack_dir == NULL) { + opkg_msg(ERROR, "Internal error: %s has a NULL tmp_unpack_dir.\n", + pkg->name); + return -1; + } + sprintf_alloc(&path, "%s/%s", pkg->tmp_unpack_dir, script); + } + + opkg_msg(INFO, "Running script %s.\n", path); + + setenv("PKG_ROOT", + pkg->dest ? pkg->dest->root_dir : conf->default_dest->root_dir, 1); + + if (! file_exists(path)) { + free(path); + return 0; + } + + sprintf_alloc(&cmd, "%s %s", path, args); + free(path); + { + const char *argv[] = {"sh", "-c", cmd, NULL}; + err = xsystem(argv); + } + free(cmd); + + if (err) { + opkg_msg(ERROR, "package \"%s\" %s script returned status %d.\n", + pkg->name, script, err); + return err; + } + + return 0; +} + +int +pkg_arch_supported(pkg_t *pkg) +{ + nv_pair_list_elt_t *l; + + if (!pkg->architecture) + return 1; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (strcmp(nv->name, pkg->architecture) == 0) { + opkg_msg(DEBUG, "Arch %s (priority %s) supported for pkg %s.\n", + nv->name, nv->value, pkg->name); + return 1; + } + } + + opkg_msg(DEBUG, "Arch %s unsupported for pkg %s.\n", + pkg->architecture, pkg->name); + return 0; +} + +void +pkg_info_preinstall_check(void) +{ + int i; + pkg_vec_t *installed_pkgs = pkg_vec_alloc(); + + /* update the file owner data structure */ + opkg_msg(INFO, "Updating file owner list.\n"); + pkg_hash_fetch_all_installed(installed_pkgs); + for (i = 0; i < installed_pkgs->len; i++) { + pkg_t *pkg = installed_pkgs->pkgs[i]; + str_list_t *installed_files = pkg_get_installed_files(pkg); /* this causes installed_files to be cached */ + str_list_elt_t *iter, *niter; + if (installed_files == NULL) { + opkg_msg(ERROR, "Failed to determine installed " + "files for pkg %s.\n", pkg->name); + break; + } + for (iter = str_list_first(installed_files), niter = str_list_next(installed_files, iter); + iter; + iter = niter, niter = str_list_next(installed_files, iter)) { + char *installed_file = (char *) iter->data; + file_hash_set_file_owner(installed_file, pkg); + } + pkg_free_installed_files(pkg); + } + pkg_vec_free(installed_pkgs); +} + +struct pkg_write_filelist_data { + pkg_t *pkg; + FILE *stream; +}; + +static void +pkg_write_filelist_helper(const char *key, void *entry_, void *data_) +{ + struct pkg_write_filelist_data *data = data_; + pkg_t *entry = entry_; + if (entry == data->pkg) { + fprintf(data->stream, "%s\n", key); + } +} + +int +pkg_write_filelist(pkg_t *pkg) +{ + struct pkg_write_filelist_data data; + char *list_file_name; + + sprintf_alloc(&list_file_name, "%s/%s.list", + pkg->dest->info_dir, pkg->name); + + opkg_msg(INFO, "Creating %s file for pkg %s.\n", + list_file_name, pkg->name); + + data.stream = fopen(list_file_name, "w"); + if (!data.stream) { + opkg_perror(ERROR, "Failed to open %s", + list_file_name); + free(list_file_name); + return -1; + } + + data.pkg = pkg; + hash_table_foreach(&conf->file_hash, pkg_write_filelist_helper, &data); + fclose(data.stream); + free(list_file_name); + + pkg->state_flag &= ~SF_FILELIST_CHANGED; + + return 0; +} + +int +pkg_write_changed_filelists(void) +{ + pkg_vec_t *installed_pkgs = pkg_vec_alloc(); + int i, err, ret = 0; + + if (conf->noaction) + return 0; + + opkg_msg(INFO, "Saving changed filelists.\n"); + + pkg_hash_fetch_all_installed(installed_pkgs); + for (i = 0; i < installed_pkgs->len; i++) { + pkg_t *pkg = installed_pkgs->pkgs[i]; + if (pkg->state_flag & SF_FILELIST_CHANGED) { + err = pkg_write_filelist(pkg); + if (err) + ret = -1; + } + } + + pkg_vec_free (installed_pkgs); + + return ret; +} diff --git a/src/libopkg/pkg.h b/src/libopkg/pkg.h new file mode 100644 index 0000000..775b656 --- /dev/null +++ b/src/libopkg/pkg.h @@ -0,0 +1,231 @@ +/* pkg.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_H +#define PKG_H + +#include "config.h" + +#include <sys/types.h> + +#include "pkg_vec.h" +#include "str_list.h" +#include "active_list.h" +#include "pkg_src.h" +#include "pkg_dest.h" +#include "opkg_conf.h" +#include "conffile_list.h" + +struct opkg_conf; + + +#define ARRAY_SIZE(array) sizeof(array) / sizeof((array)[0]) + +/* I think "Size" is currently the shortest field name */ +#define PKG_MINIMUM_FIELD_NAME_LEN 4 + +enum pkg_state_want +{ + SW_UNKNOWN = 1, + SW_INSTALL, + SW_DEINSTALL, + SW_PURGE, + SW_LAST_STATE_WANT +}; +typedef enum pkg_state_want pkg_state_want_t; + +enum pkg_state_flag +{ + SF_OK = 0, + SF_REINSTREQ = 1, + SF_HOLD = 2, /* do not upgrade version */ + SF_REPLACE = 4, /* replace this package */ + SF_NOPRUNE = 8, /* do not remove obsolete files */ + SF_PREFER = 16, /* prefer this version */ + SF_OBSOLETE = 32, /* old package in upgrade pair */ + SF_MARKED = 64, /* temporary mark */ + SF_FILELIST_CHANGED = 128, /* needs filelist written */ + SF_USER = 256, + SF_LAST_STATE_FLAG +}; +typedef enum pkg_state_flag pkg_state_flag_t; +#define SF_NONVOLATILE_FLAGS (SF_HOLD|SF_NOPRUNE|SF_PREFER|SF_OBSOLETE|SF_USER) + +enum pkg_state_status +{ + SS_NOT_INSTALLED = 1, + SS_UNPACKED, + SS_HALF_CONFIGURED, + SS_INSTALLED, + SS_HALF_INSTALLED, + SS_CONFIG_FILES, + SS_POST_INST_FAILED, + SS_REMOVAL_FAILED, + SS_LAST_STATE_STATUS +}; +typedef enum pkg_state_status pkg_state_status_t; + +struct abstract_pkg{ + char * name; + int dependencies_checked; + pkg_vec_t * pkgs; + pkg_state_status_t state_status; + pkg_state_flag_t state_flag; + + /* XXX: This should be abstract_pkg_vec_t for consistency. */ + struct abstract_pkg ** depended_upon_by; + + abstract_pkg_vec_t * provided_by; + abstract_pkg_vec_t * replaced_by; +}; + +#include "pkg_depends.h" + +/* XXX: CLEANUP: I'd like to clean up pkg_t in several ways: + + The 3 version fields should go into a single version struct. (This + is especially important since, currently, pkg->version can easily + be mistaken for pkg_verson_str_alloc(pkg) although they are very + distinct. This has been the source of multiple bugs. + + The 3 state fields could possibly also go into their own struct. + + All fields which deal with lists of packages, (Depends, + Pre-Depends, Provides, Suggests, Recommends, Enhances), should each + be handled by a single struct in pkg_t + + All string fields for which there is a small set of possible + values, (section, maintainer, architecture, maybe version?), that + are reused among different packages -- for all such packages we + should move from "char *"s to some atom datatype to share data + storage and use less memory. We might even do reference counting, + but probably not since most often we only create new pkg_t structs, + we don't often free them. */ +struct pkg +{ + char *name; + unsigned long epoch; + char *version; + char *revision; + pkg_src_t *src; + pkg_dest_t *dest; + char *architecture; + char *section; + char *maintainer; + char *description; + char *tags; + pkg_state_want_t state_want; + pkg_state_flag_t state_flag; + pkg_state_status_t state_status; + char **depends_str; + unsigned int depends_count; + char **pre_depends_str; + unsigned int pre_depends_count; + char **recommends_str; + unsigned int recommends_count; + char **suggests_str; + unsigned int suggests_count; + struct active_list list; /* Used for installing|upgrading */ + compound_depend_t * depends; + + char **conflicts_str; + compound_depend_t * conflicts; + unsigned int conflicts_count; + + char **replaces_str; + unsigned int replaces_count; + abstract_pkg_t ** replaces; + + char **provides_str; + unsigned int provides_count; + abstract_pkg_t ** provides; + + abstract_pkg_t *parent; + + char *filename; + char *local_filename; + char *tmp_unpack_dir; + char *md5sum; +#if defined HAVE_SHA256 + char *sha256sum; +#endif + unsigned long size; /* in bytes */ + unsigned long installed_size; /* in bytes */ + char *priority; + char *source; + conffile_list_t conffiles; + time_t installed_time; + /* As pointer for lazy evaluation */ + str_list_t *installed_files; + /* XXX: CLEANUP: I'd like to perhaps come up with a better + mechanism to avoid the problem here, (which is that the + installed_files list was being freed from an inner loop while + still being used within an outer loop. */ + int installed_files_ref_cnt; + int essential; + int arch_priority; +/* Adding this flag, to "force" opkg to choose a "provided_by_hand" package, if there are multiple choice */ + int provided_by_hand; + + /* this flag specifies whether the package was installed to satisfy another + * package's dependancies */ + int auto_installed; +}; + +pkg_t *pkg_new(void); +void pkg_deinit(pkg_t *pkg); +int pkg_init_from_file(pkg_t *pkg, const char *filename); +abstract_pkg_t *abstract_pkg_new(void); + +/* + * merges fields from newpkg into oldpkg. + * Forcibly sets oldpkg state_status, state_want and state_flags + */ +int pkg_merge(pkg_t *oldpkg, pkg_t *newpkg); + +char *pkg_version_str_alloc(pkg_t *pkg); + +int pkg_compare_versions(const pkg_t *pkg, const pkg_t *ref_pkg); +int pkg_name_version_and_architecture_compare(const void *a, const void *b); +int abstract_pkg_name_compare(const void *a, const void *b); + +void pkg_formatted_info(FILE *fp, pkg_t *pkg); +void pkg_formatted_field(FILE *fp, pkg_t *pkg, const char *field); + +void set_flags_from_control(pkg_t *pkg); + +void pkg_print_status(pkg_t * pkg, FILE * file); +str_list_t *pkg_get_installed_files(pkg_t *pkg); +void pkg_free_installed_files(pkg_t *pkg); +void pkg_remove_installed_files_list(pkg_t *pkg); +conffile_t *pkg_get_conffile(pkg_t *pkg, const char *file_name); +int pkg_run_script(pkg_t *pkg, const char *script, const char *args); + +/* enum mappings */ +pkg_state_want_t pkg_state_want_from_str(char *str); +pkg_state_flag_t pkg_state_flag_from_str(const char *str); +pkg_state_status_t pkg_state_status_from_str(const char *str); + +int pkg_version_satisfied(pkg_t *it, pkg_t *ref, const char *op); + +int pkg_arch_supported(pkg_t *pkg); +void pkg_info_preinstall_check(void); + +int pkg_write_filelist(pkg_t *pkg); +int pkg_write_changed_filelists(void); + +#endif diff --git a/src/libopkg/pkg_depends.c b/src/libopkg/pkg_depends.c new file mode 100644 index 0000000..1e14d1f --- /dev/null +++ b/src/libopkg/pkg_depends.c @@ -0,0 +1,931 @@ +/* pkg_depends.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <stdio.h> +#include <ctype.h> + +#include "pkg.h" +#include "opkg_utils.h" +#include "pkg_hash.h" +#include "opkg_message.h" +#include "pkg_parse.h" +#include "hash_table.h" +#include "libbb/libbb.h" + +static int parseDepends(compound_depend_t *compound_depend, char * depend_str); +static depend_t * depend_init(void); +static char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx); +static char ** merge_unresolved(char ** oldstuff, char ** newstuff); +static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg); + +static int pkg_installed_and_constraint_satisfied(pkg_t *pkg, void *cdata) +{ + depend_t *depend = (depend_t *)cdata; + if ((pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) && version_constraints_satisfied(depend, pkg)) + return 1; + else + return 0; +} + +static int pkg_constraint_satisfied(pkg_t *pkg, void *cdata) +{ + depend_t *depend = (depend_t *)cdata; + if (version_constraints_satisfied(depend, pkg)) + return 1; + else + return 0; +} + +/* returns ndependencies or negative error value */ +int +pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *unsatisfied, + char *** unresolved) +{ + pkg_t * satisfier_entry_pkg; + int i, j, k; + int count, found; + char ** the_lost; + abstract_pkg_t * ab_pkg; + + /* + * this is a setup to check for redundant/cyclic dependency checks, + * which are marked at the abstract_pkg level + */ + if (!(ab_pkg = pkg->parent)) { + opkg_msg(ERROR, "Internal error, with pkg %s.\n", pkg->name); + *unresolved = NULL; + return 0; + } + if (ab_pkg->dependencies_checked) { /* avoid duplicate or cyclic checks */ + *unresolved = NULL; + return 0; + } else { + ab_pkg->dependencies_checked = 1; /* mark it for subsequent visits */ + } + /**/ + + count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count; + if (!count){ + *unresolved = NULL; + return 0; + } + + the_lost = NULL; + + /* foreach dependency */ + for (i = 0; i < count; i++) { + compound_depend_t * compound_depend = &pkg->depends[i]; + depend_t ** possible_satisfiers = compound_depend->possibilities;; + found = 0; + satisfier_entry_pkg = NULL; + + if (compound_depend->type == GREEDY_DEPEND) { + /* foreach possible satisfier */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + abstract_pkg_t *abpkg = possible_satisfiers[j]->pkg; + abstract_pkg_vec_t *ab_provider_vec = abpkg->provided_by; + int nposs = ab_provider_vec->len; + abstract_pkg_t **ab_providers = ab_provider_vec->pkgs; + int l; + for (l = 0; l < nposs; l++) { + pkg_vec_t *test_vec = ab_providers[l]->pkgs; + /* if no depends on this one, try the first package that Provides this one */ + if (!test_vec){ /* no pkg_vec hooked up to the abstract_pkg! (need another feed?) */ + continue; + } + + /* cruise this possiblity's pkg_vec looking for an installed version */ + for (k = 0; k < test_vec->len; k++) { + pkg_t *pkg_scout = test_vec->pkgs[k]; + /* not installed, and not already known about? */ + if ((pkg_scout->state_want != SW_INSTALL) + && !pkg_scout->parent->dependencies_checked + && !is_pkg_in_pkg_vec(unsatisfied, pkg_scout)) { + char ** newstuff = NULL; + int rc; + pkg_vec_t *tmp_vec = pkg_vec_alloc (); + /* check for not-already-installed dependencies */ + rc = pkg_hash_fetch_unsatisfied_dependencies(pkg_scout, + tmp_vec, + &newstuff); + if (newstuff == NULL) { + int m; + int ok = 1; + for (m = 0; m < rc; m++) { + pkg_t *p = tmp_vec->pkgs[m]; + if (p->state_want == SW_INSTALL) + continue; + opkg_msg(DEBUG, + "Not installing %s due" + " to requirement for %s.\n", + pkg_scout->name, + p->name); + ok = 0; + break; + } + pkg_vec_free (tmp_vec); + if (ok) { + /* mark this one for installation */ + opkg_msg(NOTICE, + "Adding satisfier for greedy" + " dependence %s.\n", + pkg_scout->name); + pkg_vec_insert(unsatisfied, pkg_scout); + } + } else { + opkg_msg(DEBUG, + "Not installing %s due to " + "broken depends.\n", + pkg_scout->name); + free (newstuff); + } + } + } + } + } + + continue; + } + + /* foreach possible satisfier, look for installed package */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + depend_t *dependence_to_satisfy = possible_satisfiers[j]; + abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg; + pkg_t *satisfying_pkg = + pkg_hash_fetch_best_installation_candidate(satisfying_apkg, + pkg_installed_and_constraint_satisfied, + dependence_to_satisfy, 1); + /* Being that I can't test constraing in pkg_hash, I will test it here */ + if (satisfying_pkg != NULL) { + if (!pkg_installed_and_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) { + satisfying_pkg = NULL; + } + } + opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg); + if (satisfying_pkg != NULL) { + found = 1; + break; + } + + } + /* if nothing installed matches, then look for uninstalled satisfier */ + if (!found) { + /* foreach possible satisfier, look for installed package */ + for (j = 0; j < compound_depend->possibility_count; j++) { + /* foreach provided_by, which includes the abstract_pkg itself */ + depend_t *dependence_to_satisfy = possible_satisfiers[j]; + abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg; + pkg_t *satisfying_pkg = + pkg_hash_fetch_best_installation_candidate(satisfying_apkg, + pkg_constraint_satisfied, + dependence_to_satisfy, 1); + /* Being that I can't test constraing in pkg_hash, I will test it here too */ + if (satisfying_pkg != NULL) { + if (!pkg_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) { + satisfying_pkg = NULL; + } + } + + /* user request overrides package recommendation */ + if (satisfying_pkg != NULL + && (compound_depend->type == RECOMMEND || compound_depend->type == SUGGEST) + && (satisfying_pkg->state_want == SW_DEINSTALL || satisfying_pkg->state_want == SW_PURGE)) { + opkg_msg(NOTICE, "%s: ignoring recommendation for " + "%s at user request\n", + pkg->name, satisfying_pkg->name); + continue; + } + + opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg); + if (satisfying_pkg != NULL) { + satisfier_entry_pkg = satisfying_pkg; + break; + } + } + } + + /* we didn't find one, add something to the unsatisfied vector */ + if (!found) { + if (!satisfier_entry_pkg) { + /* failure to meet recommendations is not an error */ + if (compound_depend->type != RECOMMEND && compound_depend->type != SUGGEST) + the_lost = add_unresolved_dep(pkg, the_lost, i); + else + opkg_msg(NOTICE, + "%s: unsatisfied recommendation for %s\n", + pkg->name, + compound_depend->possibilities[0]->pkg->name); + } + else { + if (compound_depend->type == SUGGEST) { + /* just mention it politely */ + opkg_msg(NOTICE, "package %s suggests installing %s\n", + pkg->name, satisfier_entry_pkg->name); + } else { + char ** newstuff = NULL; + + if (satisfier_entry_pkg != pkg && + !is_pkg_in_pkg_vec(unsatisfied, satisfier_entry_pkg)) { + pkg_vec_insert(unsatisfied, satisfier_entry_pkg); + pkg_hash_fetch_unsatisfied_dependencies(satisfier_entry_pkg, + unsatisfied, + &newstuff); + the_lost = merge_unresolved(the_lost, newstuff); + if (newstuff) + free(newstuff); + } + } + } + } + } + *unresolved = the_lost; + + return unsatisfied->len; +} + +/*checking for conflicts !in replaces + If a packages conflicts with another but is also replacing it, I should not consider it a + really conflicts + returns 0 if conflicts <> replaces or 1 if conflicts == replaces +*/ +static int +is_pkg_a_replaces(pkg_t *pkg_scout,pkg_t *pkg) +{ + int i ; + int replaces_count = pkg->replaces_count; + abstract_pkg_t **replaces; + + if (pkg->replaces_count==0) // No replaces, it's surely a conflict + return 0; + + replaces = pkg->replaces; + + for (i = 0; i < replaces_count; i++) { + if (strcmp(pkg_scout->name,pkg->replaces[i]->name)==0) { // Found + opkg_msg(DEBUG2, "Seems I've found a replace %s %s\n", + pkg_scout->name, pkg->replaces[i]->name); + return 1; + } + } + return 0; + +} + + +pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg) +{ + pkg_vec_t * installed_conflicts, * test_vec; + compound_depend_t * conflicts; + depend_t ** possible_satisfiers; + depend_t * possible_satisfier; + int i, j, k; + int count; + abstract_pkg_t * ab_pkg; + pkg_t **pkg_scouts; + pkg_t *pkg_scout; + + /* + * this is a setup to check for redundant/cyclic dependency checks, + * which are marked at the abstract_pkg level + */ + if(!(ab_pkg = pkg->parent)){ + opkg_msg(ERROR, "Internal error: %s not in hash table\n", pkg->name); + return (pkg_vec_t *)NULL; + } + + conflicts = pkg->conflicts; + if(!conflicts){ + return (pkg_vec_t *)NULL; + } + installed_conflicts = pkg_vec_alloc(); + + count = pkg->conflicts_count; + + + + /* foreach conflict */ + for(i = 0; i < pkg->conflicts_count; i++){ + + possible_satisfiers = conflicts->possibilities; + + /* foreach possible satisfier */ + for(j = 0; j < conflicts->possibility_count; j++){ + possible_satisfier = possible_satisfiers[j]; + if (!possible_satisfier) + opkg_msg(ERROR, "Internal error: possible_satisfier=NULL\n"); + if (!possible_satisfier->pkg) + opkg_msg(ERROR, "Internal error: possible_satisfier->pkg=NULL\n"); + test_vec = possible_satisfier->pkg->pkgs; + if (test_vec) { + /* pkg_vec found, it is an actual package conflict + * cruise this possiblity's pkg_vec looking for an installed version */ + pkg_scouts = test_vec->pkgs; + for(k = 0; k < test_vec->len; k++){ + pkg_scout = pkg_scouts[k]; + if (!pkg_scout) { + opkg_msg(ERROR, "Internal error: pkg_scout=NULL\n"); + continue; + } + if ((pkg_scout->state_status == SS_INSTALLED || pkg_scout->state_want == SW_INSTALL) && + version_constraints_satisfied(possible_satisfier, pkg_scout) && !is_pkg_a_replaces(pkg_scout,pkg)){ + if (!is_pkg_in_pkg_vec(installed_conflicts, pkg_scout)){ + pkg_vec_insert(installed_conflicts, pkg_scout); + } + } + } + } + } + conflicts++; + } + + if (installed_conflicts->len) + return installed_conflicts; + pkg_vec_free(installed_conflicts); + return (pkg_vec_t *)NULL; +} + +int version_constraints_satisfied(depend_t * depends, pkg_t * pkg) +{ + pkg_t * temp; + int comparison; + + if(depends->constraint == NONE) + return 1; + + temp = pkg_new(); + + parse_version(temp, depends->version); + + comparison = pkg_compare_versions(pkg, temp); + + free (temp->version); + free(temp); + + if((depends->constraint == EARLIER) && + (comparison < 0)) + return 1; + else if((depends->constraint == LATER) && + (comparison > 0)) + return 1; + else if(comparison == 0) + return 1; + else if((depends->constraint == LATER_EQUAL) && + (comparison >= 0)) + return 1; + else if((depends->constraint == EARLIER_EQUAL) && + (comparison <= 0)) + return 1; + + return 0; +} + +int pkg_dependence_satisfiable(depend_t *depend) +{ + abstract_pkg_t *apkg = depend->pkg; + abstract_pkg_vec_t *provider_apkgs = apkg->provided_by; + int n_providers = provider_apkgs->len; + abstract_pkg_t **apkgs = provider_apkgs->pkgs; + pkg_vec_t *pkg_vec; + int n_pkgs ; + int i; + int j; + + for (i = 0; i < n_providers; i++) { + abstract_pkg_t *papkg = apkgs[i]; + pkg_vec = papkg->pkgs; + if (pkg_vec) { + n_pkgs = pkg_vec->len; + for (j = 0; j < n_pkgs; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (version_constraints_satisfied(depend, pkg)) { + return 1; + } + } + } + } + return 0; +} + +int pkg_dependence_satisfied(depend_t *depend) +{ + abstract_pkg_t *apkg = depend->pkg; + abstract_pkg_vec_t *provider_apkgs = apkg->provided_by; + int n_providers = provider_apkgs->len; + abstract_pkg_t **apkgs = provider_apkgs->pkgs; + int i; + int n_pkgs; + int j; + + for (i = 0; i < n_providers; i++) { + abstract_pkg_t *papkg = apkgs[i]; + pkg_vec_t *pkg_vec = papkg->pkgs; + if (pkg_vec) { + n_pkgs = pkg_vec->len; + for (j = 0; j < n_pkgs; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (version_constraints_satisfied(depend, pkg)) { + if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) + return 1; + } + } + } + } + return 0; +} + +static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg) +{ + int i; + pkg_t ** pkgs = vec->pkgs; + + for(i = 0; i < vec->len; i++) + if((strcmp(pkg->name, (*(pkgs + i))->name) == 0) + && (pkg_compare_versions(pkg, *(pkgs + i)) == 0) + && (strcmp(pkg->architecture, (*(pkgs + i))->architecture) == 0)) + return 1; + return 0; +} + +/** + * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0 + * otherwise. + */ +int pkg_replaces(pkg_t *pkg, pkg_t *replacee) +{ + abstract_pkg_t **replaces = pkg->replaces; + int replaces_count = pkg->replaces_count; + int replacee_provides_count = replacee->provides_count; + int i, j; + for (i = 0; i < replaces_count; i++) { + abstract_pkg_t *abstract_replacee = replaces[i]; + for (j = 0; j < replacee_provides_count; j++) { + if (replacee->provides[j] == abstract_replacee) + return 1; + } + } + return 0; +} + + +/** + * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee and 0 + * otherwise. + */ +int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflictee) +{ + compound_depend_t *conflicts = pkg->conflicts; + int conflicts_count = pkg->conflicts_count; + int i, j; + for (i = 0; i < conflicts_count; i++) { + int possibility_count = conflicts[i].possibility_count; + struct depend **possibilities = conflicts[i].possibilities; + for (j = 0; j < possibility_count; j++) { + if (possibilities[j]->pkg == conflictee) { + return 1; + } + } + } + return 0; +} + +/** + * pkg_conflicts returns 1 if pkg->conflicts contains one of + * conflictee's provides and 0 otherwise. + */ +int pkg_conflicts(pkg_t *pkg, pkg_t *conflictee) +{ + compound_depend_t *conflicts = pkg->conflicts; + int conflicts_count = pkg->conflicts_count; + abstract_pkg_t **conflictee_provides = conflictee->provides; + int conflictee_provides_count = conflictee->provides_count; + int i, j, k; + int possibility_count; + struct depend **possibilities; + abstract_pkg_t *possibility ; + + for (i = 0; i < conflicts_count; i++) { + possibility_count = conflicts[i].possibility_count; + possibilities = conflicts[i].possibilities; + for (j = 0; j < possibility_count; j++) { + possibility = possibilities[j]->pkg; + for (k = 0; k < conflictee_provides_count; k++) { + if (possibility == conflictee_provides[k]) { + return 1; + } + } + } + } + return 0; +} + +static char ** merge_unresolved(char ** oldstuff, char ** newstuff) +{ + int oldlen = 0, newlen = 0; + char ** result; + int i, j; + + if(!newstuff) + return oldstuff; + + while(oldstuff && oldstuff[oldlen]) oldlen++; + while(newstuff && newstuff[newlen]) newlen++; + + result = xrealloc(oldstuff, sizeof(char *) * (oldlen + newlen + 1)); + + for(i = oldlen, j = 0; i < (oldlen + newlen); i++, j++) + *(result + i) = *(newstuff + j); + + *(result + i) = NULL; + + return result; +} + +/* + * a kinda kludgy way to back out depends str from two different arrays (reg'l'r 'n pre) + * this is null terminated, no count is carried around + */ +char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx) +{ + int count; + char ** resized; + + count = 0; + while(the_lost && the_lost[count]) count++; + + count++; /* need one to hold the null */ + resized = xrealloc(the_lost, sizeof(char *) * (count + 1)); + resized[count - 1] = pkg_depend_str(pkg, ref_ndx); + resized[count] = NULL; + + return resized; +} + +void buildProvides(abstract_pkg_t * ab_pkg, pkg_t * pkg) +{ + int i; + + /* every pkg provides itself */ + pkg->provides_count++; + abstract_pkg_vec_insert(ab_pkg->provided_by, ab_pkg); + pkg->provides = xcalloc(pkg->provides_count, sizeof(abstract_pkg_t *)); + pkg->provides[0] = ab_pkg; + + for (i=1; i<pkg->provides_count; i++) { + abstract_pkg_t *provided_abpkg = ensure_abstract_pkg_by_name( + pkg->provides_str[i-1]); + free(pkg->provides_str[i-1]); + + pkg->provides[i] = provided_abpkg; + + abstract_pkg_vec_insert(provided_abpkg->provided_by, ab_pkg); + } + if (pkg->provides_str) + free(pkg->provides_str); +} + +void buildConflicts(pkg_t * pkg) +{ + int i; + compound_depend_t * conflicts; + + if (!pkg->conflicts_count) + return; + + conflicts = pkg->conflicts = xcalloc(pkg->conflicts_count, sizeof(compound_depend_t)); + for (i = 0; i < pkg->conflicts_count; i++) { + conflicts->type = CONFLICTS; + parseDepends(conflicts, pkg->conflicts_str[i]); + free(pkg->conflicts_str[i]); + conflicts++; + } + if (pkg->conflicts_str) + free(pkg->conflicts_str); +} + +void buildReplaces(abstract_pkg_t * ab_pkg, pkg_t * pkg) +{ + int i; + + if (!pkg->replaces_count) + return; + + pkg->replaces = xcalloc(pkg->replaces_count, sizeof(abstract_pkg_t *)); + + for(i = 0; i < pkg->replaces_count; i++){ + abstract_pkg_t *old_abpkg = ensure_abstract_pkg_by_name(pkg->replaces_str[i]); + + pkg->replaces[i] = old_abpkg; + free(pkg->replaces_str[i]); + + if (!old_abpkg->replaced_by) + old_abpkg->replaced_by = abstract_pkg_vec_alloc(); + /* if a package pkg both replaces and conflicts old_abpkg, + * then add it to the replaced_by vector so that old_abpkg + * will be upgraded to ab_pkg automatically */ + if (pkg_conflicts_abstract(pkg, old_abpkg)) + abstract_pkg_vec_insert(old_abpkg->replaced_by, ab_pkg); + } + + if (pkg->replaces_str) + free(pkg->replaces_str); +} + +void buildDepends(pkg_t * pkg) +{ + unsigned int count; + int i; + compound_depend_t * depends; + + if(!(count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count)) + return; + + depends = pkg->depends = xcalloc(count, sizeof(compound_depend_t)); + + for(i = 0; i < pkg->pre_depends_count; i++){ + parseDepends(depends, pkg->pre_depends_str[i]); + free(pkg->pre_depends_str[i]); + depends->type = PREDEPEND; + depends++; + } + if (pkg->pre_depends_str) + free(pkg->pre_depends_str); + + for(i = 0; i < pkg->depends_count; i++){ + parseDepends(depends, pkg->depends_str[i]); + free(pkg->depends_str[i]); + depends++; + } + if (pkg->depends_str) + free(pkg->depends_str); + + for(i = 0; i < pkg->recommends_count; i++){ + parseDepends(depends, pkg->recommends_str[i]); + free(pkg->recommends_str[i]); + depends->type = RECOMMEND; + depends++; + } + if(pkg->recommends_str) + free(pkg->recommends_str); + + for(i = 0; i < pkg->suggests_count; i++){ + parseDepends(depends, pkg->suggests_str[i]); + free(pkg->suggests_str[i]); + depends->type = SUGGEST; + depends++; + } + if(pkg->suggests_str) + free(pkg->suggests_str); +} + +const char* +constraint_to_str(enum version_constraint c) +{ + switch (c) { + case NONE: + return ""; + case EARLIER: + return "< "; + case EARLIER_EQUAL: + return "<= "; + case EQUAL: + return "= "; + case LATER_EQUAL: + return ">= "; + case LATER: + return "> "; + } + + return ""; +} + +/* + * Returns a printable string for pkg's dependency at the specified idx. The + * resultant string must be passed to free() by the caller. + */ +char * +pkg_depend_str(pkg_t *pkg, int idx) +{ + int i; + unsigned int len; + char *str; + compound_depend_t *cdep; + depend_t *dep; + + len = 0; + cdep = &pkg->depends[idx]; + + /* calculate string length */ + for (i=0; i<cdep->possibility_count; i++) { + dep = cdep->possibilities[i]; + + if (i != 0) + len += 3; /* space, pipe, space */ + + len += strlen(dep->pkg->name); + + if (dep->version) { + len += 2; /* space, left parenthesis */ + len += 3; /* constraint string (<=, >=, etc), space */ + len += strlen(dep->version); + len += 1; /* right parenthesis */ + } + } + + str = xmalloc(len + 1); /* +1 for the NULL terminator */ + str[0] = '\0'; + + for (i=0; i<cdep->possibility_count; i++) { + dep = cdep->possibilities[i]; + + if (i != 0) + strncat(str, " | ", len); + + strncat(str, dep->pkg->name, len); + + if (dep->version) { + strncat(str, " (", len); + strncat(str, constraint_to_str(dep->constraint), len); + strncat(str, dep->version, len); + strncat(str, ")", len); + } + } + + return str; +} + +void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg) +{ + compound_depend_t * depends; + int count, othercount; + int i, j; + abstract_pkg_t * ab_depend; + abstract_pkg_t ** temp; + + count = pkg->pre_depends_count + + pkg->depends_count + + pkg->recommends_count + + pkg->suggests_count; + + for (i = 0; i < count; i++) { + depends = &pkg->depends[i]; + if (depends->type != PREDEPEND + && depends->type != DEPEND + && depends->type != RECOMMEND) + continue; + for (j = 0; j < depends->possibility_count; j++) { + ab_depend = depends->possibilities[j]->pkg; + if (!ab_depend->depended_upon_by) { + ab_depend->depended_upon_by = + xcalloc(1, sizeof(abstract_pkg_t *)); + } + + temp = ab_depend->depended_upon_by; + othercount = 1; + while (*temp) { + temp++; + othercount++; + } + *temp = ab_pkg; + + ab_depend->depended_upon_by = + xrealloc(ab_depend->depended_upon_by, + (othercount + 1) * sizeof(abstract_pkg_t *)); + + /* the array may have been moved by realloc */ + temp = ab_depend->depended_upon_by + othercount; + *temp = NULL; + } + } +} + +static depend_t * depend_init(void) +{ + depend_t * d = xcalloc(1, sizeof(depend_t)); + d->constraint = NONE; + d->version = NULL; + d->pkg = NULL; + + return d; +} + +static int parseDepends(compound_depend_t *compound_depend, + char * depend_str) +{ + char * pkg_name, buffer[2048]; + unsigned int num_of_ors = 0; + int i; + char * src, * dest; + depend_t ** possibilities; + + /* first count the number of ored possibilities for satisfying dependency */ + src = depend_str; + while(*src) + if(*src++ == '|') + num_of_ors++; + + compound_depend->type = DEPEND; + + compound_depend->possibility_count = num_of_ors + 1; + possibilities = xcalloc((num_of_ors + 1), sizeof(depend_t *) ); + compound_depend->possibilities = possibilities; + + src = depend_str; + for(i = 0; i < num_of_ors + 1; i++){ + possibilities[i] = depend_init(); + /* gobble up just the name first */ + dest = buffer; + while(*src && + !isspace(*src) && + (*src != '(') && + (*src != '*') && + (*src != '|')) + *dest++ = *src++; + *dest = '\0'; + pkg_name = trim_xstrdup(buffer); + + /* now look at possible version info */ + + /* skip to next chars */ + if(isspace(*src)) + while(*src && isspace(*src)) src++; + + /* extract constraint and version */ + if(*src == '('){ + src++; + if(!strncmp(src, "<<", 2)){ + possibilities[i]->constraint = EARLIER; + src += 2; + } + else if(!strncmp(src, "<=", 2)){ + possibilities[i]->constraint = EARLIER_EQUAL; + src += 2; + } + else if(!strncmp(src, ">=", 2)){ + possibilities[i]->constraint = LATER_EQUAL; + src += 2; + } + else if(!strncmp(src, ">>", 2)){ + possibilities[i]->constraint = LATER; + src += 2; + } + else if(!strncmp(src, "=", 1)){ + possibilities[i]->constraint = EQUAL; + src++; + } + /* should these be here to support deprecated designations; dpkg does */ + else if(!strncmp(src, "<", 1)){ + possibilities[i]->constraint = EARLIER_EQUAL; + src++; + } + else if(!strncmp(src, ">", 1)){ + possibilities[i]->constraint = LATER_EQUAL; + src++; + } + + /* now we have any constraint, pass space to version string */ + while(isspace(*src)) src++; + + /* this would be the version string */ + dest = buffer; + while(*src && *src != ')') + *dest++ = *src++; + *dest = '\0'; + + possibilities[i]->version = trim_xstrdup(buffer); + } + /* hook up the dependency to its abstract pkg */ + possibilities[i]->pkg = ensure_abstract_pkg_by_name(pkg_name); + + free(pkg_name); + + /* now get past the ) and any possible | chars */ + while(*src && + (isspace(*src) || + (*src == ')') || + (*src == '|'))) + src++; + if (*src == '*') + { + compound_depend->type = GREEDY_DEPEND; + src++; + } + } + + return 0; +} diff --git a/src/libopkg/pkg_depends.h b/src/libopkg/pkg_depends.h new file mode 100644 index 0000000..5d1f074 --- /dev/null +++ b/src/libopkg/pkg_depends.h @@ -0,0 +1,90 @@ +/* pkg_depends.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PKG_DEPENDS_H +#define PKG_DEPENDS_H + +#include "pkg.h" +#include "pkg_hash.h" + +enum depend_type { + PREDEPEND, + DEPEND, + CONFLICTS, + GREEDY_DEPEND, + RECOMMEND, + SUGGEST +}; +typedef enum depend_type depend_type_t; + +enum version_constraint { + NONE, + EARLIER, + EARLIER_EQUAL, + EQUAL, + LATER_EQUAL, + LATER +}; +typedef enum version_constraint version_constraint_t; + +struct depend{ + version_constraint_t constraint; + char * version; + abstract_pkg_t * pkg; +}; +typedef struct depend depend_t; + +struct compound_depend{ + depend_type_t type; + int possibility_count; + struct depend ** possibilities; +}; +typedef struct compound_depend compound_depend_t; + +void buildProvides(abstract_pkg_t * ab_pkg, pkg_t * pkg); +void buildConflicts(pkg_t * pkg); +void buildReplaces(abstract_pkg_t * ab_pkg, pkg_t * pkg); +void buildDepends(pkg_t * pkg); + +/** + * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0 + * otherwise. + */ +int pkg_replaces(pkg_t *pkg, pkg_t *replacee); + +/** + * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee provides and 0 + * otherwise. + */ +int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflicts); + +/** + * pkg_conflicts returns 1 if pkg->conflicts contains one of conflictee's provides and 0 + * otherwise. + */ +int pkg_conflicts(pkg_t *pkg, pkg_t *conflicts); + +char *pkg_depend_str(pkg_t *pkg, int index); +void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg); +int version_constraints_satisfied(depend_t * depends, pkg_t * pkg); +int pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *depends, char *** unresolved); +pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg); +int pkg_dependence_satisfiable(depend_t *depend); +int pkg_dependence_satisfied(depend_t *depend); +const char* constraint_to_str(enum version_constraint c); + +#endif diff --git a/src/libopkg/pkg_dest.c b/src/libopkg/pkg_dest.c new file mode 100644 index 0000000..d56dd78 --- /dev/null +++ b/src/libopkg/pkg_dest.c @@ -0,0 +1,82 @@ +/* pkg_dest.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> + +#include "pkg_dest.h" +#include "file_util.h" +#include "sprintf_alloc.h" +#include "opkg_conf.h" +#include "opkg_cmd.h" +#include "opkg_defines.h" +#include "libbb/libbb.h" + +int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char * lists_dir) +{ + dest->name = xstrdup(name); + + /* Guarantee that dest->root_dir ends with a '/' */ + if (root_dir[strlen(root_dir) -1] == '/') { + dest->root_dir = xstrdup(root_dir); + } else { + sprintf_alloc(&dest->root_dir, "%s/", root_dir); + } + file_mkdir_hier(dest->root_dir, 0755); + + sprintf_alloc(&dest->opkg_dir, "%s%s", + dest->root_dir, OPKG_STATE_DIR_PREFIX); + file_mkdir_hier(dest->opkg_dir, 0755); + + if (lists_dir[0] == '/') + sprintf_alloc(&dest->lists_dir, "%s", lists_dir); + else + sprintf_alloc(&dest->lists_dir, "/%s", lists_dir); + + file_mkdir_hier(dest->lists_dir, 0755); + + sprintf_alloc(&dest->info_dir, "%s/%s", + dest->opkg_dir, OPKG_INFO_DIR_SUFFIX); + file_mkdir_hier(dest->info_dir, 0755); + + sprintf_alloc(&dest->status_file_name, "%s/%s", + dest->opkg_dir, OPKG_STATUS_FILE_SUFFIX); + + return 0; +} + +void pkg_dest_deinit(pkg_dest_t *dest) +{ + free(dest->name); + dest->name = NULL; + + free(dest->root_dir); + dest->root_dir = NULL; + + free(dest->opkg_dir); + dest->opkg_dir = NULL; + + free(dest->lists_dir); + dest->lists_dir = NULL; + + free(dest->info_dir); + dest->info_dir = NULL; + + free(dest->status_file_name); + dest->status_file_name = NULL; + + dest->root_dir = NULL; +} diff --git a/src/libopkg/pkg_dest.h b/src/libopkg/pkg_dest.h new file mode 100644 index 0000000..4ad417e --- /dev/null +++ b/src/libopkg/pkg_dest.h @@ -0,0 +1,39 @@ +/* pkg_dest.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_DEST_H +#define PKG_DEST_H + +#include <stdio.h> + +typedef struct pkg_dest pkg_dest_t; +struct pkg_dest +{ + char *name; + char *root_dir; + char *opkg_dir; + char *lists_dir; + char *info_dir; + char *status_file_name; + FILE *status_fp; +}; + +int pkg_dest_init(pkg_dest_t *dest, const char *name, const char *root_dir,const char *lists_dir); +void pkg_dest_deinit(pkg_dest_t *dest); + +#endif + diff --git a/src/libopkg/pkg_dest_list.c b/src/libopkg/pkg_dest_list.c new file mode 100644 index 0000000..f5f2e1d --- /dev/null +++ b/src/libopkg/pkg_dest_list.c @@ -0,0 +1,77 @@ +/* pkg_dest_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> + +#include "pkg_dest.h" +#include "void_list.h" +#include "pkg_dest_list.h" +#include "libbb/libbb.h" + +void pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data) +{ + void_list_elt_init((void_list_elt_t *) elt, data); +} + +void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt) +{ + void_list_elt_deinit((void_list_elt_t *) elt); +} + +void pkg_dest_list_init(pkg_dest_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void pkg_dest_list_deinit(pkg_dest_list_t *list) +{ + pkg_dest_list_elt_t *iter, *n; + pkg_dest_t *pkg_dest; + + list_for_each_entry_safe(iter, n, &list->head, node) { + pkg_dest = (pkg_dest_t *)iter->data; + pkg_dest_deinit(pkg_dest); + + /* malloced in pkg_dest_list_append */ + free(pkg_dest); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name, + const char *root_dir,const char *lists_dir) +{ + pkg_dest_t *pkg_dest; + + /* freed in pkg_dest_list_deinit */ + pkg_dest = xcalloc(1, sizeof(pkg_dest_t)); + pkg_dest_init(pkg_dest, name, root_dir,lists_dir); + void_list_append((void_list_t *) list, pkg_dest); + + return pkg_dest; +} + +void pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list) +{ + return (pkg_dest_list_elt_t *) void_list_pop((void_list_t *) list); +} diff --git a/src/libopkg/pkg_dest_list.h b/src/libopkg/pkg_dest_list.h new file mode 100644 index 0000000..33aef19 --- /dev/null +++ b/src/libopkg/pkg_dest_list.h @@ -0,0 +1,39 @@ +/* pkg_dest_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_DEST_LIST_H +#define PKG_DEST_LIST_H + +#include "pkg_dest.h" + +typedef struct void_list_elt pkg_dest_list_elt_t; + +typedef struct void_list pkg_dest_list_t; + +void pkg_dest_list_elt_init(pkg_dest_list_elt_t *elt, pkg_dest_t *data); +void pkg_dest_list_elt_deinit(pkg_dest_list_elt_t *elt); + +void pkg_dest_list_init(pkg_dest_list_t *list); +void pkg_dest_list_deinit(pkg_dest_list_t *list); + +pkg_dest_t *pkg_dest_list_append(pkg_dest_list_t *list, const char *name, + const char *root_dir,const char* lists_dir); +void pkg_dest_list_push(pkg_dest_list_t *list, pkg_dest_t *data); +pkg_dest_list_elt_t *pkg_dest_list_pop(pkg_dest_list_t *list); + +#endif + diff --git a/src/libopkg/pkg_extract.c b/src/libopkg/pkg_extract.c new file mode 100644 index 0000000..0f21e40 --- /dev/null +++ b/src/libopkg/pkg_extract.c @@ -0,0 +1,99 @@ +/* pkg_extract.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <stdio.h> + +#include "pkg_extract.h" +#include "libbb/libbb.h" +#include "file_util.h" +#include "sprintf_alloc.h" + +int +pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream) +{ + int err; + deb_extract(pkg->local_filename, stream, + extract_control_tar_gz + | extract_to_stream, + NULL, "control", &err); + return err; +} + +int +pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg, const char *dir, + const char *prefix) +{ + int err; + char *dir_with_prefix; + + sprintf_alloc(&dir_with_prefix, "%s/%s", dir, prefix); + + deb_extract(pkg->local_filename, stderr, + extract_control_tar_gz + | extract_all_to_fs| extract_preserve_date + | extract_unconditional, + dir_with_prefix, NULL, &err); + + free(dir_with_prefix); + return err; +} + +int +pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir) +{ + return pkg_extract_control_files_to_dir_with_prefix(pkg, dir, ""); +} + + +int +pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir) +{ + int err; + + deb_extract(pkg->local_filename, stderr, + extract_data_tar_gz + | extract_all_to_fs| extract_preserve_date + | extract_unconditional, + dir, NULL, &err); + + return err; +} + +int +pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *stream) +{ + int err; + + /* XXX: DPKG_INCOMPATIBILITY: deb_extract will extract all of the + data file names with a '.' as the first character. I've taught + opkg how to cope with the presence or absence of the '.', but + this may trip up dpkg. + + For all I know, this could actually be a bug in opkg-build. So, + I'll have to try installing some .debs and comparing the *.list + files. + + If we wanted to, we could workaround the deb_extract behavior + right here, by writing to a tmpfile, then munging things as we + wrote to the actual stream. */ + + deb_extract(pkg->local_filename, stream, + extract_quiet | extract_data_tar_gz | extract_list, + NULL, NULL, &err); + + return err; +} diff --git a/src/libopkg/pkg_extract.h b/src/libopkg/pkg_extract.h new file mode 100644 index 0000000..b83b41b --- /dev/null +++ b/src/libopkg/pkg_extract.h @@ -0,0 +1,31 @@ +/* pkg_extract.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_EXTRACT_H +#define PKG_EXTRACT_H + +#include "pkg.h" + +int pkg_extract_control_file_to_stream(pkg_t *pkg, FILE *stream); +int pkg_extract_control_files_to_dir(pkg_t *pkg, const char *dir); +int pkg_extract_control_files_to_dir_with_prefix(pkg_t *pkg, + const char *dir, + const char *prefix); +int pkg_extract_data_files_to_dir(pkg_t *pkg, const char *dir); +int pkg_extract_data_file_names_to_stream(pkg_t *pkg, FILE *file); + +#endif diff --git a/src/libopkg/pkg_hash.c b/src/libopkg/pkg_hash.c new file mode 100644 index 0000000..a99cf6b --- /dev/null +++ b/src/libopkg/pkg_hash.c @@ -0,0 +1,735 @@ +/* opkg_hash.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <stdio.h> + +#include "hash_table.h" +#include "release.h" +#include "pkg.h" +#include "opkg_message.h" +#include "pkg_vec.h" +#include "pkg_hash.h" +#include "parse_util.h" +#include "pkg_parse.h" +#include "opkg_utils.h" +#include "sprintf_alloc.h" +#include "file_util.h" +#include "libbb/libbb.h" + +void +pkg_hash_init(void) +{ + hash_table_init("pkg-hash", &conf->pkg_hash, + OPKG_CONF_DEFAULT_HASH_LEN); +} + +static void +free_pkgs(const char *key, void *entry, void *data) +{ + int i; + abstract_pkg_t *ab_pkg; + + /* Each entry in the hash table is an abstract package, which contains + * a list of packages that provide the abstract package. + */ + + ab_pkg = (abstract_pkg_t*) entry; + + if (ab_pkg->pkgs) { + for (i = 0; i < ab_pkg->pkgs->len; i++) { + pkg_deinit (ab_pkg->pkgs->pkgs[i]); + free (ab_pkg->pkgs->pkgs[i]); + } + } + + abstract_pkg_vec_free (ab_pkg->provided_by); + abstract_pkg_vec_free (ab_pkg->replaced_by); + pkg_vec_free (ab_pkg->pkgs); + free (ab_pkg->depended_upon_by); + free (ab_pkg->name); + free (ab_pkg); +} + +void +pkg_hash_deinit(void) +{ + hash_table_foreach(&conf->pkg_hash, free_pkgs, NULL); + hash_table_deinit(&conf->pkg_hash); +} + +int +dist_hash_add_from_file(const char *lists_dir, pkg_src_t *dist) +{ + nv_pair_list_elt_t *l; + char *list_file, *subname; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + sprintf_alloc(&subname, "%s-%s", dist->name, nv->name); + sprintf_alloc(&list_file, "%s/%s", lists_dir, subname); + + if (file_exists(list_file)) { + if (pkg_hash_add_from_file(list_file, dist, NULL, 0)) { + free(list_file); + return -1; + } + pkg_src_list_append (&conf->pkg_src_list, subname, dist->value, "__dummy__", 0); + } + + free(list_file); + } + + return 0; +} + + +int +pkg_hash_add_from_file(const char *file_name, + pkg_src_t *src, pkg_dest_t *dest, int is_status_file) +{ + pkg_t *pkg; + FILE *fp; + char *buf; + const size_t len = 4096; + int ret = 0; + + fp = fopen(file_name, "r"); + if (fp == NULL) { + opkg_perror(ERROR, "Failed to open %s", file_name); + return -1; + } + + buf = xmalloc(len); + + do { + pkg = pkg_new(); + pkg->src = src; + pkg->dest = dest; + + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, 0, + &buf, len); + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + if (ret) { + pkg_deinit (pkg); + free(pkg); + if (ret == -1) + break; + if (ret == 1) + /* Probably a blank line, continue parsing. */ + ret = 0; + continue; + } + + if (!pkg->architecture || !pkg->arch_priority) { + char *version_str = pkg_version_str_alloc(pkg); + opkg_msg(NOTICE, "Package %s version %s has no " + "valid architecture, ignoring.\n", + pkg->name, version_str); + free(version_str); + continue; + } + + hash_insert_pkg(pkg, is_status_file); + + } while (!feof(fp)); + + free(buf); + fclose(fp); + + return ret; +} + +/* + * Load in feed files from the cached "src" and/or "src/gz" locations. + */ +int +pkg_hash_load_feeds(void) +{ + pkg_src_list_elt_t *iter; + pkg_src_t *src, *subdist; + char *list_file, *lists_dir; + + opkg_msg(INFO, "\n"); + + lists_dir = conf->restrict_to_default_dest ? + conf->default_dest->lists_dir : conf->lists_dir; + + for (iter = void_list_first(&conf->dist_src_list); iter; + iter = void_list_next(&conf->dist_src_list, iter)) { + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name); + + if (file_exists(list_file)) { + int i; + release_t *release = release_new(); + if(release_init_from_file(release, list_file)) { + free(list_file); + return -1; + } + + unsigned int ncomp; + const char **comps = release_comps(release, &ncomp); + subdist = (pkg_src_t *) xmalloc(sizeof(pkg_src_t)); + memcpy(subdist, src, sizeof(pkg_src_t)); + + for(i = 0; i < ncomp; i++){ + subdist->name = NULL; + sprintf_alloc(&subdist->name, "%s-%s", src->name, comps[i]); + if (dist_hash_add_from_file(lists_dir, subdist)) { + free(subdist->name); free(subdist); + free(list_file); + return -1; + } + } + free(subdist->name); free(subdist); + } + free(list_file); + } + + for (iter = void_list_first(&conf->pkg_src_list); iter; + iter = void_list_next(&conf->pkg_src_list, iter)) { + + src = (pkg_src_t *)iter->data; + + sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name); + + if (file_exists(list_file)) { + if (pkg_hash_add_from_file(list_file, src, NULL, 0)) { + free(list_file); + return -1; + } + } + free(list_file); + } + + return 0; +} + +/* + * Load in status files from the configured "dest"s. + */ +int +pkg_hash_load_status_files(void) +{ + pkg_dest_list_elt_t *iter; + pkg_dest_t *dest; + + opkg_msg(INFO, "\n"); + + for (iter = void_list_first(&conf->pkg_dest_list); iter; + iter = void_list_next(&conf->pkg_dest_list, iter)) { + + dest = (pkg_dest_t *)iter->data; + + if (file_exists(dest->status_file_name)) { + if (pkg_hash_add_from_file(dest->status_file_name, NULL, dest, 1)) + return -1; + } + } + + return 0; +} + +static abstract_pkg_t * +abstract_pkg_fetch_by_name(const char * pkg_name) +{ + return (abstract_pkg_t *)hash_table_get(&conf->pkg_hash, pkg_name); +} + +pkg_t * +pkg_hash_fetch_best_installation_candidate(abstract_pkg_t *apkg, + int (*constraint_fcn)(pkg_t *pkg, void *cdata), + void *cdata, int quiet) +{ + int i, j; + int nprovides = 0; + int nmatching = 0; + int wrong_arch_found = 0; + pkg_vec_t *matching_pkgs; + abstract_pkg_vec_t *matching_apkgs; + abstract_pkg_vec_t *provided_apkg_vec; + abstract_pkg_t **provided_apkgs; + abstract_pkg_vec_t *providers; + pkg_t *latest_installed_parent = NULL; + pkg_t *latest_matching = NULL; + pkg_t *priorized_matching = NULL; + pkg_t *held_pkg = NULL; + pkg_t *good_pkg_by_name = NULL; + + if (apkg == NULL || apkg->provided_by == NULL || (apkg->provided_by->len == 0)) + return NULL; + + matching_pkgs = pkg_vec_alloc(); + matching_apkgs = abstract_pkg_vec_alloc(); + providers = abstract_pkg_vec_alloc(); + + opkg_msg(DEBUG, "Best installation candidate for %s:\n", apkg->name); + + provided_apkg_vec = apkg->provided_by; + nprovides = provided_apkg_vec->len; + provided_apkgs = provided_apkg_vec->pkgs; + if (nprovides > 1) + opkg_msg(DEBUG, "apkg=%s nprovides=%d.\n", apkg->name, nprovides); + + /* accumulate all the providers */ + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *provider_apkg = provided_apkgs[i]; + opkg_msg(DEBUG, "Adding %s to providers.\n", provider_apkg->name); + abstract_pkg_vec_insert(providers, provider_apkg); + } + nprovides = providers->len; + + for (i = 0; i < nprovides; i++) { + abstract_pkg_t *provider_apkg = abstract_pkg_vec_get(providers, i); + abstract_pkg_t *replacement_apkg = NULL; + pkg_vec_t *vec; + + if (provider_apkg->replaced_by && provider_apkg->replaced_by->len) { + replacement_apkg = provider_apkg->replaced_by->pkgs[0]; + if (provider_apkg->replaced_by->len > 1) { + opkg_msg(NOTICE, "Multiple replacers for %s, " + "using first one (%s).\n", + provider_apkg->name, replacement_apkg->name); + } + } + + if (replacement_apkg) + opkg_msg(DEBUG, "replacement_apkg=%s for provider_apkg=%s.\n", + replacement_apkg->name, provider_apkg->name); + + if (replacement_apkg && (replacement_apkg != provider_apkg)) { + if (abstract_pkg_vec_contains(providers, replacement_apkg)) + continue; + else + provider_apkg = replacement_apkg; + } + + if (!(vec = provider_apkg->pkgs)) { + opkg_msg(DEBUG, "No pkgs for provider_apkg %s.\n", + provider_apkg->name); + continue; + } + + + /* now check for supported architecture */ + { + int max_count = 0; + + /* count packages matching max arch priority and keep track of last one */ + for (j=0; j<vec->len; j++) { + pkg_t *maybe = vec->pkgs[j]; + opkg_msg(DEBUG, "%s arch=%s arch_priority=%d version=%s.\n", + maybe->name, maybe->architecture, + maybe->arch_priority, maybe->version); + /* We make sure not to add the same package twice. Need to search for the reason why + they show up twice sometimes. */ + if ((maybe->arch_priority > 0) && (! pkg_vec_contains(matching_pkgs, maybe))) { + max_count++; + abstract_pkg_vec_insert(matching_apkgs, maybe->parent); + pkg_vec_insert(matching_pkgs, maybe); + } + } + + if (vec->len > 0 && matching_pkgs->len < 1) + wrong_arch_found = 1; + } + } + + if (matching_pkgs->len < 1) { + if (wrong_arch_found) + opkg_msg(ERROR, "Packages for %s found, but" + " incompatible with the architectures configured\n", + apkg->name); + pkg_vec_free(matching_pkgs); + abstract_pkg_vec_free(matching_apkgs); + abstract_pkg_vec_free(providers); + return NULL; + } + + + if (matching_pkgs->len > 1) + pkg_vec_sort(matching_pkgs, pkg_name_version_and_architecture_compare); + if (matching_apkgs->len > 1) + abstract_pkg_vec_sort(matching_pkgs, abstract_pkg_name_compare); + + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + if (constraint_fcn(matching, cdata)) { + opkg_msg(DEBUG, "Candidate: %s %s.\n", + matching->name, matching->version) ; + good_pkg_by_name = matching; + /* It has been provided by hand, so it is what user want */ + if (matching->provided_by_hand == 1) + break; + } + } + + + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + latest_matching = matching; + if (matching->parent->state_status == SS_INSTALLED || matching->parent->state_status == SS_UNPACKED) + latest_installed_parent = matching; + if (matching->state_flag & (SF_HOLD|SF_PREFER)) { + if (held_pkg) + opkg_msg(NOTICE, "Multiple packages (%s and %s) providing" + " same name marked HOLD or PREFER. " + "Using latest.\n", + held_pkg->name, matching->name); + held_pkg = matching; + } + } + + if (!good_pkg_by_name && !held_pkg && !latest_installed_parent && matching_apkgs->len > 1 && !quiet) { + int prio = 0; + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + if (matching->arch_priority > prio) { + priorized_matching = matching; + prio = matching->arch_priority; + opkg_msg(DEBUG, "Match %s with priority %i.\n", + matching->name, prio); + } + } + + } + + if (conf->verbosity >= INFO && matching_apkgs->len > 1) { + opkg_msg(INFO, "%d matching pkgs for apkg=%s:\n", + matching_pkgs->len, apkg->name); + for (i = 0; i < matching_pkgs->len; i++) { + pkg_t *matching = matching_pkgs->pkgs[i]; + opkg_msg(INFO, "%s %s %s\n", + matching->name, matching->version, + matching->architecture); + } + } + + nmatching = matching_apkgs->len; + + pkg_vec_free(matching_pkgs); + abstract_pkg_vec_free(matching_apkgs); + abstract_pkg_vec_free(providers); + + if (good_pkg_by_name) { /* We found a good candidate, we will install it */ + return good_pkg_by_name; + } + if (held_pkg) { + opkg_msg(INFO, "Using held package %s.\n", held_pkg->name); + return held_pkg; + } + if (latest_installed_parent) { + opkg_msg(INFO, "Using latest version of installed package %s.\n", + latest_installed_parent->name); + return latest_installed_parent; + } + if (priorized_matching) { + opkg_msg(INFO, "Using priorized matching %s %s %s.\n", + priorized_matching->name, priorized_matching->version, + priorized_matching->architecture); + return priorized_matching; + } + if (nmatching > 1) { + opkg_msg(INFO, "No matching pkg out of %d matching_apkgs.\n", + nmatching); + return NULL; + } + if (latest_matching) { + opkg_msg(INFO, "Using latest matching %s %s %s.\n", + latest_matching->name, latest_matching->version, + latest_matching->architecture); + return latest_matching; + } + return NULL; +} + +static int +pkg_name_constraint_fcn(pkg_t *pkg, void *cdata) +{ + const char *name = (const char *)cdata; + + if (strcmp(pkg->name, name) == 0) + return 1; + else + return 0; +} + +static pkg_vec_t * +pkg_vec_fetch_by_name(const char *pkg_name) +{ + abstract_pkg_t * ab_pkg; + + if(!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name))) + return NULL; + + if (ab_pkg->pkgs) + return ab_pkg->pkgs; + + if (ab_pkg->provided_by) { + abstract_pkg_t *abpkg = abstract_pkg_vec_get(ab_pkg->provided_by, 0); + if (abpkg != NULL) + return abpkg->pkgs; + else + return ab_pkg->pkgs; + } + + return NULL; +} + + +pkg_t * +pkg_hash_fetch_best_installation_candidate_by_name(const char *name) +{ + abstract_pkg_t *apkg = NULL; + + if (!(apkg = abstract_pkg_fetch_by_name(name))) + return NULL; + + return pkg_hash_fetch_best_installation_candidate(apkg, + pkg_name_constraint_fcn, apkg->name, 0); +} + + +pkg_t * +pkg_hash_fetch_by_name_version(const char *pkg_name, const char * version) +{ + pkg_vec_t * vec; + int i; + char *version_str = NULL; + + if(!(vec = pkg_vec_fetch_by_name(pkg_name))) + return NULL; + + for(i = 0; i < vec->len; i++) { + version_str = pkg_version_str_alloc(vec->pkgs[i]); + if(!strcmp(version_str, version)) { + free(version_str); + break; + } + free(version_str); + } + + if(i == vec->len) + return NULL; + + return vec->pkgs[i]; +} + +pkg_t * +pkg_hash_fetch_installed_by_name_dest(const char *pkg_name, pkg_dest_t *dest) +{ + pkg_vec_t * vec; + int i; + + if (!(vec = pkg_vec_fetch_by_name(pkg_name))) { + return NULL; + } + + for (i = 0; i < vec->len; i++) + if((vec->pkgs[i]->state_status == SS_INSTALLED + || vec->pkgs[i]->state_status == SS_UNPACKED) + && vec->pkgs[i]->dest == dest) { + return vec->pkgs[i]; + } + + return NULL; +} + +pkg_t * +pkg_hash_fetch_installed_by_name(const char *pkg_name) +{ + pkg_vec_t * vec; + int i; + + if (!(vec = pkg_vec_fetch_by_name(pkg_name))) { + return NULL; + } + + for (i = 0; i < vec->len; i++) { + if (vec->pkgs[i]->state_status == SS_INSTALLED + || vec->pkgs[i]->state_status == SS_UNPACKED) { + return vec->pkgs[i]; + } + } + + return NULL; +} + + +static void +pkg_hash_fetch_available_helper(const char *pkg_name, void *entry, void *data) +{ + int j; + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *all = (pkg_vec_t *)data; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + pkg_vec_insert(all, pkg); + } +} + +void +pkg_hash_fetch_available(pkg_vec_t *all) +{ + hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_available_helper, + all); +} + +static void +pkg_hash_fetch_all_installed_helper(const char *pkg_name, void *entry, void *data) +{ + abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry; + pkg_vec_t *all = (pkg_vec_t *)data; + pkg_vec_t *pkg_vec = ab_pkg->pkgs; + int j; + + if (!pkg_vec) + return; + + for (j = 0; j < pkg_vec->len; j++) { + pkg_t *pkg = pkg_vec->pkgs[j]; + if (pkg->state_status == SS_INSTALLED + || pkg->state_status == SS_UNPACKED) + pkg_vec_insert(all, pkg); + } +} + +void +pkg_hash_fetch_all_installed(pkg_vec_t *all) +{ + hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_all_installed_helper, + all); +} + +/* + * This assumes that the abstract pkg doesn't exist. + */ +static abstract_pkg_t * +add_new_abstract_pkg_by_name(const char *pkg_name) +{ + abstract_pkg_t *ab_pkg; + + ab_pkg = abstract_pkg_new(); + + ab_pkg->name = xstrdup(pkg_name); + hash_table_insert(&conf->pkg_hash, pkg_name, ab_pkg); + + return ab_pkg; +} + + +abstract_pkg_t * +ensure_abstract_pkg_by_name(const char *pkg_name) +{ + abstract_pkg_t * ab_pkg; + + if (!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name))) + ab_pkg = add_new_abstract_pkg_by_name(pkg_name); + + return ab_pkg; +} + +void +hash_insert_pkg(pkg_t *pkg, int set_status) +{ + abstract_pkg_t * ab_pkg; + + ab_pkg = ensure_abstract_pkg_by_name(pkg->name); + if (!ab_pkg->pkgs) + ab_pkg->pkgs = pkg_vec_alloc(); + + if (pkg->state_status == SS_INSTALLED) { + ab_pkg->state_status = SS_INSTALLED; + } else if (pkg->state_status == SS_UNPACKED) { + ab_pkg->state_status = SS_UNPACKED; + } + + buildDepends(pkg); + + buildProvides(ab_pkg, pkg); + + /* Need to build the conflicts graph before replaces for correct + * calculation of replaced_by relation. + */ + buildConflicts(pkg); + + buildReplaces(ab_pkg, pkg); + + buildDependedUponBy(pkg, ab_pkg); + + pkg_vec_insert_merge(ab_pkg->pkgs, pkg, set_status); + pkg->parent = ab_pkg; +} + +static const char * +strip_offline_root(const char *file_name) +{ + unsigned int len; + + if (conf->offline_root) { + len = strlen(conf->offline_root); + if (strncmp(file_name, conf->offline_root, len) == 0) + file_name += len; + } + + return file_name; +} + +void +file_hash_remove(const char *file_name) +{ + file_name = strip_offline_root(file_name); + hash_table_remove(&conf->file_hash, file_name); +} + +pkg_t * +file_hash_get_file_owner(const char *file_name) +{ + file_name = strip_offline_root(file_name); + return hash_table_get(&conf->file_hash, file_name); +} + +void +file_hash_set_file_owner(const char *file_name, pkg_t *owning_pkg) +{ + pkg_t *old_owning_pkg; + + file_name = strip_offline_root(file_name); + + old_owning_pkg = hash_table_get(&conf->file_hash, file_name); + hash_table_insert(&conf->file_hash, file_name, owning_pkg); + + if (old_owning_pkg) { + pkg_get_installed_files(old_owning_pkg); + str_list_remove_elt(old_owning_pkg->installed_files, file_name); + pkg_free_installed_files(old_owning_pkg); + + /* mark this package to have its filelist written */ + old_owning_pkg->state_flag |= SF_FILELIST_CHANGED; + owning_pkg->state_flag |= SF_FILELIST_CHANGED; + } +} diff --git a/src/libopkg/pkg_hash.h b/src/libopkg/pkg_hash.h new file mode 100644 index 0000000..b3cf3d1 --- /dev/null +++ b/src/libopkg/pkg_hash.h @@ -0,0 +1,56 @@ +/* pkg_hash.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PKG_HASH_H +#define PKG_HASH_H + +#include "pkg.h" +#include "pkg_src.h" +#include "pkg_dest.h" +#include "hash_table.h" + + +void pkg_hash_init(void); +void pkg_hash_deinit(void); + +void pkg_hash_fetch_available(pkg_vec_t *available); + +int dist_hash_add_from_file(const char *file_name, pkg_src_t *dist); +int pkg_hash_add_from_file(const char *file_name, pkg_src_t *src, + pkg_dest_t *dest, int is_status_file); +int pkg_hash_load_feeds(void); +int pkg_hash_load_status_files(void); + +void hash_insert_pkg(pkg_t *pkg, int set_status); + +abstract_pkg_t * ensure_abstract_pkg_by_name(const char * pkg_name); +void pkg_hash_fetch_all_installed(pkg_vec_t *installed); +pkg_t * pkg_hash_fetch_by_name_version(const char *pkg_name, + const char * version); +pkg_t *pkg_hash_fetch_best_installation_candidate(abstract_pkg_t *apkg, + int (*constraint_fcn)(pkg_t *pkg, void *data), void *cdata, int quiet); +pkg_t *pkg_hash_fetch_best_installation_candidate_by_name(const char *name); +pkg_t *pkg_hash_fetch_installed_by_name(const char *pkg_name); +pkg_t *pkg_hash_fetch_installed_by_name_dest(const char *pkg_name, + pkg_dest_t *dest); + +void file_hash_remove(const char *file_name); +pkg_t *file_hash_get_file_owner(const char *file_name); +void file_hash_set_file_owner(const char *file_name, pkg_t *pkg); + +#endif + diff --git a/src/libopkg/pkg_parse.c b/src/libopkg/pkg_parse.c new file mode 100644 index 0000000..406220b --- /dev/null +++ b/src/libopkg/pkg_parse.c @@ -0,0 +1,285 @@ +/* pkg_parse.c - the opkg package management system + + Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com> + + Steven M. Ayer + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> +#include <ctype.h> + +#include "opkg_utils.h" +#include "pkg_parse.h" +#include "libbb/libbb.h" + +#include "parse_util.h" + +static void +parse_status(pkg_t *pkg, const char *sstr) +{ + char sw_str[64], sf_str[64], ss_str[64]; + + if (sscanf(sstr, "Status: %63s %63s %63s", + sw_str, sf_str, ss_str) != 3) { + opkg_msg(ERROR, "Failed to parse Status line for %s\n", + pkg->name); + return; + } + + pkg->state_want = pkg_state_want_from_str(sw_str); + pkg->state_flag = pkg_state_flag_from_str(sf_str); + pkg->state_status = pkg_state_status_from_str(ss_str); +} + +static void +parse_conffiles(pkg_t *pkg, const char *cstr) +{ + char file_name[1024], md5sum[35]; + + if (sscanf(cstr, "%1023s %34s", file_name, md5sum) != 2) { + opkg_msg(ERROR, "Failed to parse Conffiles line for %s\n", + pkg->name); + return; + } + + conffile_list_append(&pkg->conffiles, file_name, md5sum); +} + +int +parse_version(pkg_t *pkg, const char *vstr) +{ + char *colon; + + if (strncmp(vstr, "Version:", 8) == 0) + vstr += 8; + + while (*vstr && isspace(*vstr)) + vstr++; + + colon = strchr(vstr, ':'); + if (colon) { + errno = 0; + pkg->epoch = strtoul(vstr, NULL, 10); + if (errno) { + opkg_perror(ERROR, "%s: invalid epoch", pkg->name); + } + vstr = ++colon; + } else { + pkg->epoch= 0; + } + + pkg->version = xstrdup(vstr); + pkg->revision = strrchr(pkg->version,'-'); + + if (pkg->revision) + *pkg->revision++ = '\0'; + + return 0; +} + +static int +get_arch_priority(const char *arch) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (strcmp(nv->name, arch) == 0) + return strtol(nv->value, NULL, 0); + } + return 0; +} + +int +pkg_parse_line(void *ptr, const char *line, uint mask) +{ + pkg_t *pkg = (pkg_t *) ptr; + + /* these flags are a bit hackish... */ + static int reading_conffiles = 0, reading_description = 0; + int ret = 0; + + /* Exclude globally masked fields. */ + mask |= conf->pfm; + + /* Flip the semantics of the mask. */ + mask ^= PFM_ALL; + + switch (*line) { + case 'A': + if ((mask & PFM_ARCHITECTURE ) && is_field("Architecture", line)) { + pkg->architecture = parse_simple("Architecture", line); + pkg->arch_priority = get_arch_priority(pkg->architecture); + } else if ((mask & PFM_AUTO_INSTALLED) && is_field("Auto-Installed", line)) { + char *tmp = parse_simple("Auto-Installed", line); + if (strcmp(tmp, "yes") == 0) + pkg->auto_installed = 1; + free(tmp); + } + break; + + case 'C': + if ((mask & PFM_CONFFILES) && is_field("Conffiles", line)) { + reading_conffiles = 1; + reading_description = 0; + goto dont_reset_flags; + } + else if ((mask & PFM_CONFLICTS) && is_field("Conflicts", line)) + pkg->conflicts_str = parse_list(line, &pkg->conflicts_count, ',', 0); + break; + + case 'D': + if ((mask & PFM_DESCRIPTION) && is_field("Description", line)) { + pkg->description = parse_simple("Description", line); + reading_conffiles = 0; + reading_description = 1; + goto dont_reset_flags; + } else if ((mask & PFM_DEPENDS) && is_field("Depends", line)) + pkg->depends_str = parse_list(line, &pkg->depends_count, ',', 0); + break; + + case 'E': + if((mask & PFM_ESSENTIAL) && is_field("Essential", line)) { + char *tmp = parse_simple("Essential", line); + if (strcmp(tmp, "yes") == 0) + pkg->essential = 1; + free(tmp); + } + break; + + case 'F': + if((mask & PFM_FILENAME) && is_field("Filename", line)) + pkg->filename = parse_simple("Filename", line); + break; + + case 'I': + if ((mask & PFM_INSTALLED_SIZE) && is_field("Installed-Size", line)) { + char *tmp = parse_simple("Installed-Size", line); + pkg->installed_size = strtoul(tmp, NULL, 0); + free (tmp); + } else if ((mask & PFM_INSTALLED_TIME) && is_field("Installed-Time", line)) { + char *tmp = parse_simple("Installed-Time", line); + pkg->installed_time = strtoul(tmp, NULL, 0); + free (tmp); + } + break; + + case 'M': + if ((mask & PFM_MD5SUM) && is_field("MD5sum:", line)) + pkg->md5sum = parse_simple("MD5sum", line); + /* The old opkg wrote out status files with the wrong + * case for MD5sum, let's parse it either way */ + else if ((mask & PFM_MD5SUM) && is_field("MD5Sum:", line)) + pkg->md5sum = parse_simple("MD5Sum", line); + else if((mask & PFM_MAINTAINER) && is_field("Maintainer", line)) + pkg->maintainer = parse_simple("Maintainer", line); + break; + + case 'P': + if ((mask & PFM_PACKAGE) && is_field("Package", line)) + pkg->name = parse_simple("Package", line); + else if ((mask & PFM_PRIORITY) && is_field("Priority", line)) + pkg->priority = parse_simple("Priority", line); + else if ((mask & PFM_PROVIDES) && is_field("Provides", line)) + pkg->provides_str = parse_list(line, &pkg->provides_count, ',', 0); + else if ((mask & PFM_PRE_DEPENDS) && is_field("Pre-Depends", line)) + pkg->pre_depends_str = parse_list(line, &pkg->pre_depends_count, ',', 0); + break; + + case 'R': + if ((mask & PFM_RECOMMENDS) && is_field("Recommends", line)) + pkg->recommends_str = parse_list(line, &pkg->recommends_count, ',', 0); + else if ((mask & PFM_REPLACES) && is_field("Replaces", line)) + pkg->replaces_str = parse_list(line, &pkg->replaces_count, ',', 0); + + break; + + case 'S': + if ((mask & PFM_SECTION) && is_field("Section", line)) + pkg->section = parse_simple("Section", line); +#ifdef HAVE_SHA256 + else if ((mask & PFM_SHA256SUM) && is_field("SHA256sum", line)) + pkg->sha256sum = parse_simple("SHA256sum", line); +#endif + else if ((mask & PFM_SIZE) && is_field("Size", line)) { + char *tmp = parse_simple("Size", line); + pkg->size = strtoul(tmp, NULL, 0); + free (tmp); + } else if ((mask & PFM_SOURCE) && is_field("Source", line)) + pkg->source = parse_simple("Source", line); + else if ((mask & PFM_STATUS) && is_field("Status", line)) + parse_status(pkg, line); + else if ((mask & PFM_SUGGESTS) && is_field("Suggests", line)) + pkg->suggests_str = parse_list(line, &pkg->suggests_count, ',', 0); + break; + + case 'T': + if ((mask & PFM_TAGS) && is_field("Tags", line)) + pkg->tags = parse_simple("Tags", line); + break; + + case 'V': + if ((mask & PFM_VERSION) && is_field("Version", line)) + parse_version(pkg, line); + break; + + case ' ': + if ((mask & PFM_DESCRIPTION) && reading_description) { + pkg->description = xrealloc(pkg->description, + strlen(pkg->description) + + 1 + strlen(line) + 1); + strcat(pkg->description, "\n"); + strcat(pkg->description, (line)); + goto dont_reset_flags; + } else if ((mask & PFM_CONFFILES) && reading_conffiles) { + parse_conffiles(pkg, line); + goto dont_reset_flags; + } + + /* FALLTHROUGH */ + default: + /* For package lists, signifies end of package. */ + if(line_is_blank(line)) { + ret = 1; + break; + } + } + + reading_description = 0; + reading_conffiles = 0; + +dont_reset_flags: + + return ret; +} + +int +pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask) +{ + int ret; + char *buf; + const size_t len = 4096; + + buf = xmalloc(len); + ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, mask, &buf, len); + if (pkg->name == NULL) { + /* probably just a blank line */ + ret = 1; + } + free(buf); + + return ret; +} diff --git a/src/libopkg/pkg_parse.h b/src/libopkg/pkg_parse.h new file mode 100644 index 0000000..4e2b8e0 --- /dev/null +++ b/src/libopkg/pkg_parse.h @@ -0,0 +1,57 @@ +/* pkg_parse.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PKG_PARSE_H +#define PKG_PARSE_H + +#include "pkg.h" + +int parse_version(pkg_t *pkg, const char *raw); +int pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask); +int pkg_parse_line(void *ptr, const char *line, uint mask); + +/* package field mask */ +#define PFM_ARCHITECTURE (1 << 1) +#define PFM_AUTO_INSTALLED (1 << 2) +#define PFM_CONFFILES (1 << 3) +#define PFM_CONFLICTS (1 << 4) +#define PFM_DESCRIPTION (1 << 5) +#define PFM_DEPENDS (1 << 6) +#define PFM_ESSENTIAL (1 << 7) +#define PFM_FILENAME (1 << 8) +#define PFM_INSTALLED_SIZE (1 << 9) +#define PFM_INSTALLED_TIME (1 << 10) +#define PFM_MD5SUM (1 << 11) +#define PFM_MAINTAINER (1 << 12) +#define PFM_PACKAGE (1 << 13) +#define PFM_PRIORITY (1 << 14) +#define PFM_PROVIDES (1 << 15) +#define PFM_PRE_DEPENDS (1 << 16) +#define PFM_RECOMMENDS (1 << 17) +#define PFM_REPLACES (1 << 18) +#define PFM_SECTION (1 << 19) +#define PFM_SHA256SUM (1 << 20) +#define PFM_SIZE (1 << 21) +#define PFM_SOURCE (1 << 22) +#define PFM_STATUS (1 << 23) +#define PFM_SUGGESTS (1 << 24) +#define PFM_TAGS (1 << 25) +#define PFM_VERSION (1 << 26) + +#define PFM_ALL (~(uint)0) + +#endif diff --git a/src/libopkg/pkg_src.c b/src/libopkg/pkg_src.c new file mode 100644 index 0000000..690fef6 --- /dev/null +++ b/src/libopkg/pkg_src.c @@ -0,0 +1,39 @@ +/* pkg_src.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "pkg_src.h" +#include "libbb/libbb.h" + +int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip) +{ + src->gzip = gzip; + src->name = xstrdup(name); + src->value = xstrdup(base_url); + if (extra_data) + src->extra_data = xstrdup(extra_data); + else + src->extra_data = NULL; + return 0; +} + +void pkg_src_deinit(pkg_src_t *src) +{ + free (src->name); + free (src->value); + if (src->extra_data) + free (src->extra_data); +} diff --git a/src/libopkg/pkg_src.h b/src/libopkg/pkg_src.h new file mode 100644 index 0000000..b1a95a5 --- /dev/null +++ b/src/libopkg/pkg_src.h @@ -0,0 +1,34 @@ +/* pkg_src.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_SRC_H +#define PKG_SRC_H + +#include "nv_pair.h" + +typedef struct +{ + char *name; + char *value; + char *extra_data; + int gzip; +} pkg_src_t; + +int pkg_src_init(pkg_src_t *src, const char *name, const char *base_url, const char *extra_data, int gzip); +void pkg_src_deinit(pkg_src_t *src); + +#endif diff --git a/src/libopkg/pkg_src_list.c b/src/libopkg/pkg_src_list.c new file mode 100644 index 0000000..7ad1b41 --- /dev/null +++ b/src/libopkg/pkg_src_list.c @@ -0,0 +1,64 @@ +/* pkg_src_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "pkg_src_list.h" +#include "void_list.h" +#include "libbb/libbb.h" + +void pkg_src_list_init(pkg_src_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void pkg_src_list_deinit(pkg_src_list_t *list) +{ + pkg_src_list_elt_t *iter, *n; + pkg_src_t *pkg_src; + + list_for_each_entry_safe(iter, n, &list->head, node) { + pkg_src = (pkg_src_t *)iter->data; + pkg_src_deinit(pkg_src); + + /* malloced in pkg_src_list_append */ + free(pkg_src); + iter->data = NULL; + } + void_list_deinit((void_list_t *) list); +} + +pkg_src_t *pkg_src_list_append(pkg_src_list_t *list, + const char *name, const char *base_url, const char *extra_data, + int gzip) +{ + /* freed in pkg_src_list_deinit */ + pkg_src_t *pkg_src = xcalloc(1, sizeof(pkg_src_t)); + pkg_src_init(pkg_src, name, base_url, extra_data, gzip); + + void_list_append((void_list_t *) list, pkg_src); + + return pkg_src; +} + +void pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data) +{ + void_list_push((void_list_t *) list, data); +} + +pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list) +{ + return (pkg_src_list_elt_t *) void_list_pop((void_list_t *) list); +} diff --git a/src/libopkg/pkg_src_list.h b/src/libopkg/pkg_src_list.h new file mode 100644 index 0000000..529f013 --- /dev/null +++ b/src/libopkg/pkg_src_list.h @@ -0,0 +1,44 @@ +/* pkg_src_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef PKG_SRC_LIST_H +#define PKG_SRC_LIST_H + +#include "pkg_src.h" +#include "void_list.h" + +typedef struct void_list_elt pkg_src_list_elt_t; + +typedef struct void_list pkg_src_list_t; + +static inline int pkg_src_list_empty(pkg_src_list_t *list) +{ + return void_list_empty((void_list_t *)list); +} + +void pkg_src_list_elt_init(pkg_src_list_elt_t *elt, nv_pair_t *data); +void pkg_src_list_elt_deinit(pkg_src_list_elt_t *elt); + +void pkg_src_list_init(pkg_src_list_t *list); +void pkg_src_list_deinit(pkg_src_list_t *list); + +pkg_src_t *pkg_src_list_append(pkg_src_list_t *list, const char *name, const char *root_dir, const char *extra_data, int gzip); +void pkg_src_list_push(pkg_src_list_t *list, pkg_src_t *data); +pkg_src_list_elt_t *pkg_src_list_pop(pkg_src_list_t *list); + +#endif + diff --git a/src/libopkg/pkg_vec.c b/src/libopkg/pkg_vec.c new file mode 100644 index 0000000..472962c --- /dev/null +++ b/src/libopkg/pkg_vec.c @@ -0,0 +1,208 @@ +/* pkg_vec.c - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#include <stdio.h> +#include <fnmatch.h> + +#include "pkg.h" +#include "opkg_message.h" +#include "libbb/libbb.h" + +pkg_vec_t * pkg_vec_alloc(void) +{ + pkg_vec_t * vec = xcalloc(1, sizeof(pkg_vec_t)); + vec->pkgs = NULL; + vec->len = 0; + + return vec; +} + +void pkg_vec_free(pkg_vec_t *vec) +{ + if (!vec) + return; + + if (vec->pkgs) + free(vec->pkgs); + + free(vec); +} + +/* + * assumption: all names in a vector are identical + * assumption: all version strings are trimmed, + * so identical versions have identical version strings, + * implying identical packages; let's marry these + */ +void pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status) +{ + int i; + int found = 0; + + /* look for a duplicate pkg by name, version, and architecture */ + for (i = 0; i < vec->len; i++){ + opkg_msg(DEBUG2, "%s %s arch=%s vs. %s %s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture, + vec->pkgs[i]->name, vec->pkgs[i]->version, + vec->pkgs[i]->architecture); + /* if the name,ver,arch matches, or the name matches and the + * package is marked deinstall/hold */ + if ((!strcmp(pkg->name, vec->pkgs[i]->name)) + && ((pkg->state_want == SW_DEINSTALL + && (pkg->state_flag & SF_HOLD)) + || ((pkg_compare_versions(pkg, vec->pkgs[i]) == 0) + && (!strcmp(pkg->architecture, vec->pkgs[i]->architecture))))) { + found = 1; + opkg_msg(DEBUG2, "Duplicate for pkg=%s version=%s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture); + break; + } + } + + /* we didn't find one, add it */ + if (!found){ + opkg_msg(DEBUG2, "Adding new pkg=%s version=%s arch=%s.\n", + pkg->name, pkg->version, pkg->architecture); + pkg_vec_insert(vec, pkg); + return; + } + + /* update the one that we have */ + opkg_msg(DEBUG2, "Merging %s %s arch=%s, set_status=%d.\n", + pkg->name, pkg->version, pkg->architecture, set_status); + if (set_status) { + /* This is from the status file, + * so need to merge with existing database */ + pkg_merge(pkg, vec->pkgs[i]); + } + + /* overwrite the old one */ + pkg_deinit(vec->pkgs[i]); + free(vec->pkgs[i]); + vec->pkgs[i] = pkg; +} + +void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg) +{ + vec->pkgs = xrealloc(vec->pkgs, (vec->len + 1) * sizeof(pkg_t *)); + vec->pkgs[vec->len] = (pkg_t *)pkg; + vec->len++; +} + +int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg) +{ + int i; + for (i = 0; i < vec->len; i++) + if (vec->pkgs[i] == apkg) + return 1; + return 0; +} + +void pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar) +{ + qsort(vec->pkgs, vec->len, sizeof(pkg_t *), compar); +} + +int pkg_vec_clear_marks(pkg_vec_t *vec) +{ + int npkgs = vec->len; + int i; + for (i = 0; i < npkgs; i++) { + pkg_t *pkg = vec->pkgs[i]; + pkg->state_flag &= ~SF_MARKED; + } + return 0; +} + +int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern) +{ + int matching_count = 0; + pkg_t **pkgs = vec->pkgs; + int npkgs = vec->len; + int i; + for (i = 0; i < npkgs; i++) { + pkg_t *pkg = pkgs[i]; + if (fnmatch(pattern, pkg->name, 0)==0) { + pkg->state_flag |= SF_MARKED; + matching_count++; + } + } + return matching_count; +} + + +abstract_pkg_vec_t * abstract_pkg_vec_alloc(void) +{ + abstract_pkg_vec_t * vec ; + vec = xcalloc(1, sizeof(abstract_pkg_vec_t)); + vec->pkgs = NULL; + vec->len = 0; + + return vec; +} + +void abstract_pkg_vec_free(abstract_pkg_vec_t *vec) +{ + if (!vec) + return; + free(vec->pkgs); + free(vec); +} + +/* + * assumption: all names in a vector are unique + */ +void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg) +{ + vec->pkgs = xrealloc(vec->pkgs, (vec->len + 1) * sizeof(abstract_pkg_t *)); + vec->pkgs[vec->len] = pkg; + vec->len++; +} + +abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i) +{ + if (vec->len > i) + return vec->pkgs[i]; + else + return NULL; +} + +int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg) +{ + int i; + for (i = 0; i < vec->len; i++) + if (vec->pkgs[i] == apkg) + return 1; + return 0; +} + +void abstract_pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar) +{ + qsort(vec->pkgs, vec->len, sizeof(pkg_t *), compar); +} + +int pkg_compare_names(const void *p1, const void *p2) +{ + const pkg_t *pkg1 = *(const pkg_t **)p1; + const pkg_t *pkg2 = *(const pkg_t **)p2; + if (pkg1->name == NULL) + return 1; + if (pkg2->name == NULL) + return -1; + return(strcmp(pkg1->name, pkg2->name)); +} + diff --git a/src/libopkg/pkg_vec.h b/src/libopkg/pkg_vec.h new file mode 100644 index 0000000..8ee1673 --- /dev/null +++ b/src/libopkg/pkg_vec.h @@ -0,0 +1,63 @@ +/* pkg_vec.h - the opkg package management system + + Steven M. Ayer + + Copyright (C) 2002 Compaq Computer Corporation + + 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, 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. +*/ + +#ifndef PKG_VEC_H +#define PKG_VEC_H + +typedef struct pkg pkg_t; +typedef struct abstract_pkg abstract_pkg_t; +typedef struct pkg_vec pkg_vec_t; +typedef struct abstract_pkg_vec abstract_pkg_vec_t; + +#include "opkg_conf.h" + +struct pkg_vec +{ + pkg_t **pkgs; + unsigned int len; +}; + +struct abstract_pkg_vec +{ + abstract_pkg_t **pkgs; + unsigned int len; +}; + + +pkg_vec_t * pkg_vec_alloc(void); +void pkg_vec_free(pkg_vec_t *vec); + +void pkg_vec_insert_merge(pkg_vec_t *vec, pkg_t *pkg, int set_status); +void pkg_vec_insert(pkg_vec_t *vec, const pkg_t *pkg); +int pkg_vec_contains(pkg_vec_t *vec, pkg_t *apkg); + +typedef int (*compare_fcn_t)(const void *, const void *); +void pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar); + +int pkg_vec_clear_marks(pkg_vec_t *vec); +int pkg_vec_mark_if_matches(pkg_vec_t *vec, const char *pattern); + +abstract_pkg_vec_t * abstract_pkg_vec_alloc(void); +void abstract_pkg_vec_free(abstract_pkg_vec_t *vec); +void abstract_pkg_vec_insert(abstract_pkg_vec_t *vec, abstract_pkg_t *pkg); +abstract_pkg_t * abstract_pkg_vec_get(abstract_pkg_vec_t *vec, int i); +int abstract_pkg_vec_contains(abstract_pkg_vec_t *vec, abstract_pkg_t *apkg); +void abstract_pkg_vec_sort(pkg_vec_t *vec, compare_fcn_t compar); + +int pkg_compare_names(const void *p1, const void *p2); +#endif + diff --git a/src/libopkg/release.c b/src/libopkg/release.c new file mode 100644 index 0000000..1b6e838 --- /dev/null +++ b/src/libopkg/release.c @@ -0,0 +1,342 @@ +/* release.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#include <unistd.h> +#include <ctype.h> + +#include "release.h" +#include "opkg_utils.h" +#include "libbb/libbb.h" + +#include "opkg_download.h" +#include "sprintf_alloc.h" + +#include "release_parse.h" + +#include "parse_util.h" +#include "file_util.h" + +static void +release_init(release_t *release) +{ + release->name = NULL; + release->datestring = NULL; + release->architectures = NULL; + release->architectures_count = 0; + release->components = NULL; + release->components_count = 0; + release->complist = NULL; + release->complist_count = 0; +} + +release_t * +release_new(void) +{ + release_t *release; + + release = xcalloc(1, sizeof(release_t)); + release_init(release); + + return release; +} + +void +release_deinit(release_t *release) +{ + int i; + + free(release->name); + free(release->datestring); + + for(i = 0; i < release->architectures_count; i++){ + free(release->architectures[i]); + } + free(release->architectures); + + for(i = 0; i < release->components_count; i++){ + free(release->components[i]); + } + free(release->components); + + for(i = 0; i < release->complist_count; i++){ + free(release->complist[i]); + } + free(release->complist); + +} + +int +release_init_from_file(release_t *release, const char *filename) +{ + int err = 0; + FILE *release_file; + + release_file = fopen(filename, "r"); + if (release_file == NULL) { + opkg_perror(ERROR, "Failed to open %s", filename); + return -1; + } + + err=release_parse_from_stream(release, release_file); + if (!err) { + if (!release_arch_supported(release)) { + opkg_msg(ERROR, "No valid architecture found on Release file.\n"); + err = -1; + } + } + + return err; +} + +const char * +item_in_list(const char *comp, char **complist, const unsigned int count) +{ + int i; + + if (!complist) + return comp; + + for(i = 0; i < count; i++){ + if (strcmp(comp, complist[i]) == 0) + return complist[i]; + } + + return NULL; +} + +int +release_arch_supported(release_t *release) +{ + nv_pair_list_elt_t *l; + + list_for_each_entry(l , &conf->arch_list.head, node) { + nv_pair_t *nv = (nv_pair_t *)l->data; + if (item_in_list(nv->name, release->architectures, release->architectures_count)) { + opkg_msg(DEBUG, "Arch %s (priority %s) supported for dist %s.\n", + nv->name, nv->value, release->name); + return 1; + } + } + + return 0; +} + +int +release_comps_supported(release_t *release, const char *complist) +{ + int ret = 1; + int i; + + if (complist) { + release->complist = parse_list(complist, &release->complist_count, ' ', 1); + for(i = 0; i < release->complist_count; i++){ + if (!item_in_list(release->complist[i], release->components, release->components_count)) { + opkg_msg(ERROR, "Component %s not supported for dist %s.\n", + release->complist[i], release->name); + ret = 0; + } + } + } + + return ret; +} + +const char ** +release_comps(release_t *release, unsigned int *count) +{ + char **comps = release->complist; + + if (!comps) { + comps = release->components; + *count = release->components_count; + } else { + *count = release->complist_count; + } + + return (const char **)comps; +} + +int +release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir) +{ + int ret = 0; + unsigned int ncomp; + const char **comps = release_comps(release, &ncomp); + nv_pair_list_elt_t *l; + int i; + + for(i = 0; i < ncomp; i++){ + int err = 0; + char *prefix; + + sprintf_alloc(&prefix, "%s/dists/%s/%s/binary", dist->value, dist->name, + comps[i]); + + list_for_each_entry(l , &conf->arch_list.head, node) { + char *url; + char *tmp_file_name, *list_file_name; + char *subpath = NULL; + + nv_pair_t *nv = (nv_pair_t *)l->data; + + sprintf_alloc(&list_file_name, "%s/%s-%s-%s", lists_dir, dist->name, comps[i], nv->name); + + sprintf_alloc(&tmp_file_name, "%s/%s-%s-%s%s", tmpdir, dist->name, comps[i], nv->name, ".gz"); + + sprintf_alloc(&subpath, "%s/binary-%s/%s", comps[i], nv->name, dist->gzip ? "Packages.gz" : "Packages"); + + if (dist->gzip) { + sprintf_alloc(&url, "%s-%s/Packages.gz", prefix, nv->name); + err = opkg_download(url, tmp_file_name, NULL, NULL, 1); + if (!err) { + err = release_verify_file(release, tmp_file_name, subpath); + if (err) { + unlink (tmp_file_name); + unlink (list_file_name); + } + } + if (!err) { + FILE *in, *out; + opkg_msg(NOTICE, "Inflating %s.\n", url); + in = fopen (tmp_file_name, "r"); + out = fopen (list_file_name, "w"); + if (in && out) { + err = unzip (in, out); + if (err) + opkg_msg(INFO, "Corrumpt file at %s.\n", url); + } else + err = 1; + if (in) + fclose (in); + if (out) + fclose (out); + unlink (tmp_file_name); + } + free(url); + } + + if (err) { + sprintf_alloc(&url, "%s-%s/Packages", prefix, nv->name); + err = opkg_download(url, list_file_name, NULL, NULL, 1); + if (!err) { + err = release_verify_file(release, tmp_file_name, subpath); + if (err) + unlink (list_file_name); + } + free(url); + } + + free(tmp_file_name); + free(list_file_name); + } + + if(err) + ret = 1; + + free(prefix); + } + + return ret; +} + +int +release_get_size(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->md5sums) { + cksum = cksum_list_find(release->md5sums, pathname); + return cksum->size; + } + +#ifdef HAVE_SHA256 + if (release->sha256sums) { + cksum = cksum_list_find(release->sha256sums, pathname); + return cksum->size; + } +#endif + + return -1; +} + +const char * +release_get_md5(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->md5sums) { + cksum = cksum_list_find(release->md5sums, pathname); + return cksum->value; + } + + return '\0'; +} + +#ifdef HAVE_SHA256 +const char * +release_get_sha256(release_t *release, const char *pathname) +{ + const cksum_t *cksum; + + if (release->sha256sums) { + cksum = cksum_list_find(release->sha256sums, pathname); + return cksum->value; + } + + return '\0'; +} +#endif + +int +release_verify_file(release_t *release, const char* file_name, const char *pathname) +{ + struct stat f_info; + char *f_md5 = NULL; + const char *md5 = release_get_md5(release, pathname); +#ifdef HAVE_SHA256 + char *f_sha256 = NULL; + const char *sha256 = release_get_sha256(release, pathname); +#endif + int ret = 0; + + if (stat(file_name, &f_info) || (f_info.st_size!=release_get_size(release, pathname))) { + opkg_msg(ERROR, "Size verification failed for %s - %s.\n", release->name, pathname); + ret = 1; + } else { + + f_md5 = file_md5sum_alloc(file_name); +#ifdef HAVE_SHA256 + f_sha256 = file_sha256sum_alloc(file_name); +#endif + + if (md5 && strcmp(md5, f_md5)) { + opkg_msg(ERROR, "MD5 verification failed for %s - %s.\n", release->name, pathname); + ret = 1; +#ifdef HAVE_SHA256 + } else if (sha256 && strcmp(sha256, f_sha256)) { + opkg_msg(ERROR, "SHA256 verification failed for %s - %s.\n", release->name, pathname); + ret = 1; +#endif + } + + } + + free(f_md5); +#ifdef HAVE_SHA256 + free(f_sha256); +#endif + + return ret; +} diff --git a/src/libopkg/release.h b/src/libopkg/release.h new file mode 100644 index 0000000..239dcca --- /dev/null +++ b/src/libopkg/release.h @@ -0,0 +1,53 @@ +/* release.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#ifndef RELEASE_H +#define RELEASE_H + +#include <stdio.h> +#include "pkg.h" +#include "cksum_list.h" + +struct release +{ + char *name; + char *datestring; + char **architectures; + unsigned int architectures_count; + char **components; + unsigned int components_count; + cksum_list_t *md5sums; +#ifdef HAVE_SHA256 + cksum_list_t *sha256sums; +#endif + char **complist; + unsigned int complist_count; +}; + +typedef struct release release_t; + +release_t *release_new(void); +void release_deinit(release_t *release); +int release_init_from_file(release_t *release, const char *filename); + +int release_arch_supported(release_t *release); +int release_comps_supported(release_t *release, const char *complist); +int release_download(release_t *release, pkg_src_t *dist, char *lists_dir, char *tmpdir); + +const char **release_comps(release_t *release, unsigned int *count); + +int release_verify_file(release_t *release, const char *filename, const char *pathname); + +#endif diff --git a/src/libopkg/release_parse.c b/src/libopkg/release_parse.c new file mode 100644 index 0000000..f411045 --- /dev/null +++ b/src/libopkg/release_parse.c @@ -0,0 +1,126 @@ +/* release_parse.c - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#include "config.h" + +#include <stdio.h> + +#include "release.h" +#include "release_parse.h" +#include "libbb/libbb.h" +#include "parse_util.h" + +static int +release_parse_line(void *ptr, const char *line, uint mask) +{ + release_t *release = (release_t *) ptr; + + int ret = 0; + unsigned int count = 0; + char **list = 0; + static int reading_md5sums = 0; +#ifdef HAVE_SHA256 + static int reading_sha256sums = 0; +#endif + + switch (*line) { + case 'A': + if (is_field("Architectures", line)) { + release->architectures = parse_list(line, &release->architectures_count, ' ', 0); + } + break; + + case 'C': + if (is_field("Codename", line)) { + release->name = parse_simple("Codename", line); + } + else if (is_field("Components", line)) { + release->components = parse_list(line, &release->components_count, ' ', 0); + } + break; + + case 'D': + if (is_field("Date", line)) { + release->datestring = parse_simple("Date", line); + } + break; + + case 'M': + if (is_field("MD5sum", line)) { + reading_md5sums = 1; + if (release->md5sums == NULL) { + release->md5sums = xcalloc(1, sizeof(cksum_list_t)); + cksum_list_init(release->md5sums); + } + goto dont_reset_flags; + } + break; + +#ifdef HAVE_SHA256 + case 'S': + if (is_field("SHA256", line)) { + reading_sha256sums = 1; + if (release->sha256sums == NULL) { + release->sha256sums = xcalloc(1, sizeof(cksum_list_t)); + cksum_list_init(release->sha256sums); + } + goto dont_reset_flags; + } + break; +#endif + + case ' ': + if (reading_md5sums) { + list = parse_list(line, &count, ' ', 1); + cksum_list_append(release->md5sums, list); + goto dont_reset_flags; + } +#ifdef HAVE_SHA256 + else if (reading_sha256sums) { + list = parse_list(line, &count, ' ', 1); + cksum_list_append(release->sha256sums, list); + goto dont_reset_flags; + } +#endif + break; + + default: + ret = 1; + } + + reading_md5sums = 0; +#ifdef HAVE_SHA256 + reading_sha256sums = 0; +#endif + +dont_reset_flags: + + return ret; +} + +int +release_parse_from_stream(release_t *release, FILE *fp) +{ + int ret; + char *buf; + const size_t len = 4096; + + buf = xmalloc(len); + ret = parse_from_stream_nomalloc(release_parse_line, release, fp, 0, &buf, len); + free(buf); + + return ret; +} + diff --git a/src/libopkg/release_parse.h b/src/libopkg/release_parse.h new file mode 100644 index 0000000..5840df6 --- /dev/null +++ b/src/libopkg/release_parse.h @@ -0,0 +1,21 @@ +/* release_parse.h - the opkg package management system + + Copyright (C) 2010,2011 Javier Palacios + + 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, 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. +*/ + +#ifndef RELEASE_PARSE_H +#define RELEASE_PARSE_H + +int release_parse_from_stream(release_t *release, FILE *fp); + +#endif diff --git a/src/libopkg/sha256.c b/src/libopkg/sha256.c new file mode 100644 index 0000000..0ad9444 --- /dev/null +++ b/src/libopkg/sha256.c @@ -0,0 +1,554 @@ +/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or + memory blocks according to the NIST specification FIPS-180-2. + + Copyright (C) 2005, 2006, 2008 Free Software Foundation, 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 3 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by David Madore, considerably copypasting from + Scott G. Miller's sha1.c +*/ + +#include <config.h> + +#include "sha256.h" + +#include <stddef.h> +#include <string.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 256 bit block of data (eight 32 bit ints) and + intializes it to the start constants of the SHA256 algorithm. This + must be called before using hash in the call to sha256_hash +*/ +void +sha256_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0x6a09e667UL; + ctx->state[1] = 0xbb67ae85UL; + ctx->state[2] = 0x3c6ef372UL; + ctx->state[3] = 0xa54ff53aUL; + ctx->state[4] = 0x510e527fUL; + ctx->state[5] = 0x9b05688cUL; + ctx->state[6] = 0x1f83d9abUL; + ctx->state[7] = 0x5be0cd19UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +void +sha224_init_ctx (struct sha256_ctx *ctx) +{ + ctx->state[0] = 0xc1059ed8UL; + ctx->state[1] = 0x367cd507UL; + ctx->state[2] = 0x3070dd17UL; + ctx->state[3] = 0xf70e5939UL; + ctx->state[4] = 0xffc00b31UL; + ctx->state[5] = 0x68581511UL; + ctx->state[6] = 0x64f98fa7UL; + ctx->state[7] = 0xbefa4fa4UL; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Copy the value from v into the memory location pointed to by *cp, + If your architecture allows unaligned access this is equivalent to + * (uint32_t *) cp = v */ +static inline void +set_uint32 (char *cp, uint32_t v) +{ + memcpy (cp, &v, sizeof v); +} + +/* Put result from CTX in first 32 bytes following RESBUF. The result + must be in little endian byte order. */ +void * +sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 8; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +void * +sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf) +{ + int i; + char *r = resbuf; + + for (i = 0; i < 7; i++) + set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +static void +sha256_conclude_ctx (struct sha256_ctx *ctx) +{ + /* Take yet unprocessed bytes into account. */ + size_t bytes = ctx->buflen; + size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + /* Put the 64-bit file length in *bits* at the end of the buffer. + Use set_uint32 rather than a simple assignment, to avoid risk of + unaligned access. */ + set_uint32 ((char *) &ctx->buffer[size - 2], + SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29))); + set_uint32 ((char *) &ctx->buffer[size - 1], + SWAP (ctx->total[0] << 3)); + + memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + + /* Process last bytes. */ + sha256_process_block (ctx->buffer, size * 4, ctx); +} + +void * +sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha256_read_ctx (ctx, resbuf); +} + +void * +sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf) +{ + sha256_conclude_ctx (ctx); + return sha224_read_ctx (ctx, resbuf); +} + +/* Compute SHA256 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 bytes + beginning at RESBLOCK. */ +int +sha256_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha256_finish_ctx (&ctx, resblock); + return 0; +} + +/* FIXME: Avoid code duplication */ +int +sha224_stream (FILE *stream, void *resblock) +{ + struct sha256_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha256_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha256_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha224_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +sha256_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha256_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha256_finish_ctx (&ctx, resblock); +} + +void * +sha224_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha256_ctx ctx; + + /* Initialize the computation context. */ + sha224_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha256_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha224_finish_ctx (&ctx, resblock); +} + +void +sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, + &((char *) ctx->buffer)[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + sha256_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&((char *) ctx->buffer)[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + sha256_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[16], left_over); + } + ctx->buflen = left_over; + } +} + +/* --- Code below is the primary difference between sha1.c and sha256.c --- */ + +/* SHA256 round constants */ +#define K(I) sha256_round_constants[I] +static const uint32_t sha256_round_constants[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, +}; + +/* Round functions. */ +#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) +#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void +sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx) +{ + const uint32_t *words = buffer; + size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t x[16]; + uint32_t a = ctx->state[0]; + uint32_t b = ctx->state[1]; + uint32_t c = ctx->state[2]; + uint32_t d = ctx->state[3]; + uint32_t e = ctx->state[4]; + uint32_t f = ctx->state[5]; + uint32_t g = ctx->state[6]; + uint32_t h = ctx->state[7]; + + /* First increment the byte count. FIPS PUB 180-2 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + +#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) +#define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) +#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) +#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) + +#define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \ + + S0(x[(I-15)&0x0f]) + x[I&0x0f] \ + , x[I&0x0f] = tm ) + +#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ + t1 = H + SS1(E) \ + + F1(E,F,G) \ + + K \ + + M; \ + D += t1; H = t0 + t1; \ + } while(0) + + while (words < endp) + { + uint32_t tm; + uint32_t t0, t1; + int t; + /* FIXME: see sha1.c for a better implementation. */ + for (t = 0; t < 16; t++) + { + x[t] = SWAP (*words); + words++; + } + + R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); + R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); + R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); + R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); + R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); + R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); + R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); + R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); + R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); + R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); + R( g, h, a, b, c, d, e, f, K(10), x[10] ); + R( f, g, h, a, b, c, d, e, K(11), x[11] ); + R( e, f, g, h, a, b, c, d, K(12), x[12] ); + R( d, e, f, g, h, a, b, c, K(13), x[13] ); + R( c, d, e, f, g, h, a, b, K(14), x[14] ); + R( b, c, d, e, f, g, h, a, K(15), x[15] ); + R( a, b, c, d, e, f, g, h, K(16), M(16) ); + R( h, a, b, c, d, e, f, g, K(17), M(17) ); + R( g, h, a, b, c, d, e, f, K(18), M(18) ); + R( f, g, h, a, b, c, d, e, K(19), M(19) ); + R( e, f, g, h, a, b, c, d, K(20), M(20) ); + R( d, e, f, g, h, a, b, c, K(21), M(21) ); + R( c, d, e, f, g, h, a, b, K(22), M(22) ); + R( b, c, d, e, f, g, h, a, K(23), M(23) ); + R( a, b, c, d, e, f, g, h, K(24), M(24) ); + R( h, a, b, c, d, e, f, g, K(25), M(25) ); + R( g, h, a, b, c, d, e, f, K(26), M(26) ); + R( f, g, h, a, b, c, d, e, K(27), M(27) ); + R( e, f, g, h, a, b, c, d, K(28), M(28) ); + R( d, e, f, g, h, a, b, c, K(29), M(29) ); + R( c, d, e, f, g, h, a, b, K(30), M(30) ); + R( b, c, d, e, f, g, h, a, K(31), M(31) ); + R( a, b, c, d, e, f, g, h, K(32), M(32) ); + R( h, a, b, c, d, e, f, g, K(33), M(33) ); + R( g, h, a, b, c, d, e, f, K(34), M(34) ); + R( f, g, h, a, b, c, d, e, K(35), M(35) ); + R( e, f, g, h, a, b, c, d, K(36), M(36) ); + R( d, e, f, g, h, a, b, c, K(37), M(37) ); + R( c, d, e, f, g, h, a, b, K(38), M(38) ); + R( b, c, d, e, f, g, h, a, K(39), M(39) ); + R( a, b, c, d, e, f, g, h, K(40), M(40) ); + R( h, a, b, c, d, e, f, g, K(41), M(41) ); + R( g, h, a, b, c, d, e, f, K(42), M(42) ); + R( f, g, h, a, b, c, d, e, K(43), M(43) ); + R( e, f, g, h, a, b, c, d, K(44), M(44) ); + R( d, e, f, g, h, a, b, c, K(45), M(45) ); + R( c, d, e, f, g, h, a, b, K(46), M(46) ); + R( b, c, d, e, f, g, h, a, K(47), M(47) ); + R( a, b, c, d, e, f, g, h, K(48), M(48) ); + R( h, a, b, c, d, e, f, g, K(49), M(49) ); + R( g, h, a, b, c, d, e, f, K(50), M(50) ); + R( f, g, h, a, b, c, d, e, K(51), M(51) ); + R( e, f, g, h, a, b, c, d, K(52), M(52) ); + R( d, e, f, g, h, a, b, c, K(53), M(53) ); + R( c, d, e, f, g, h, a, b, K(54), M(54) ); + R( b, c, d, e, f, g, h, a, K(55), M(55) ); + R( a, b, c, d, e, f, g, h, K(56), M(56) ); + R( h, a, b, c, d, e, f, g, K(57), M(57) ); + R( g, h, a, b, c, d, e, f, K(58), M(58) ); + R( f, g, h, a, b, c, d, e, K(59), M(59) ); + R( e, f, g, h, a, b, c, d, K(60), M(60) ); + R( d, e, f, g, h, a, b, c, K(61), M(61) ); + R( c, d, e, f, g, h, a, b, K(62), M(62) ); + R( b, c, d, e, f, g, h, a, K(63), M(63) ); + + a = ctx->state[0] += a; + b = ctx->state[1] += b; + c = ctx->state[2] += c; + d = ctx->state[3] += d; + e = ctx->state[4] += e; + f = ctx->state[5] += f; + g = ctx->state[6] += g; + h = ctx->state[7] += h; + } +} diff --git a/src/libopkg/sha256.h b/src/libopkg/sha256.h new file mode 100644 index 0000000..6a9aed4 --- /dev/null +++ b/src/libopkg/sha256.h @@ -0,0 +1,91 @@ +/* Declarations of functions and data types used for SHA256 and SHA224 sum + library functions. + Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, 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 3 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef SHA256_H +# define SHA256_H 1 + +# include <stdio.h> +# include <stdint.h> + +# ifdef __cplusplus +extern "C" { +# endif + +/* Structure to save state of computation between the single steps. */ +struct sha256_ctx +{ + uint32_t state[8]; + + uint32_t total[2]; + size_t buflen; + uint32_t buffer[32]; +}; + +enum { SHA224_DIGEST_SIZE = 224 / 8 }; +enum { SHA256_DIGEST_SIZE = 256 / 8 }; + +/* Initialize structure containing state of computation. */ +extern void sha256_init_ctx (struct sha256_ctx *ctx); +extern void sha224_init_ctx (struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void sha256_process_block (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void sha256_process_bytes (const void *buffer, size_t len, + struct sha256_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 32 (28) bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. */ +extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 32 (28) bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +extern void *sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf); +extern void *sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf); + + +/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The + resulting message digest number will be written into the 32 (28) bytes + beginning at RESBLOCK. */ +extern int sha256_stream (FILE *stream, void *resblock); +extern int sha224_stream (FILE *stream, void *resblock); + +/* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha256_buffer (const char *buffer, size_t len, void *resblock); +extern void *sha224_buffer (const char *buffer, size_t len, void *resblock); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/libopkg/sprintf_alloc.c b/src/libopkg/sprintf_alloc.c new file mode 100644 index 0000000..aef8e06 --- /dev/null +++ b/src/libopkg/sprintf_alloc.c @@ -0,0 +1,49 @@ +/* sprintf_alloc.c -- like sprintf with memory allocation + + Copyright (C) 2010 Ubiq Technologies <graham.gower@gmail.com> + + 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, 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. +*/ + +#include <stdarg.h> + +#include "sprintf_alloc.h" +#include "libbb/libbb.h" + +void +sprintf_alloc(char **str, const char *fmt, ...) +{ + va_list ap; + int n; + unsigned int size = 0; + + *str = NULL; + + for (;;) { + va_start(ap, fmt); + n = vsnprintf (*str, size, fmt, ap); + va_end(ap); + + if (n < 0) { + fprintf(stderr, "%s: encountered an output or encoding" + " error during vsnprintf.\n", + __FUNCTION__); + exit(EXIT_FAILURE); + } + + if (n < size) + break; + + /* Truncated, try again with more space. */ + size = n+1; + *str = xrealloc(*str, size); + } +} diff --git a/src/libopkg/sprintf_alloc.h b/src/libopkg/sprintf_alloc.h new file mode 100644 index 0000000..bcf42a4 --- /dev/null +++ b/src/libopkg/sprintf_alloc.h @@ -0,0 +1,23 @@ +/* sprintf_alloca.c -- like sprintf with memory allocation + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef SPRINTF_ALLOC_H +#define SPRINTF_ALLOC_H + +void sprintf_alloc(char **str, const char *fmt, ...); + +#endif diff --git a/src/libopkg/str_list.c b/src/libopkg/str_list.c new file mode 100644 index 0000000..d3a0179 --- /dev/null +++ b/src/libopkg/str_list.c @@ -0,0 +1,112 @@ +/* str_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "str_list.h" +#include "libbb/libbb.h" + +void str_list_elt_init(str_list_elt_t *elt, char *data) +{ + void_list_elt_init((void_list_elt_t *) elt, data); +} + +void str_list_elt_deinit(str_list_elt_t *elt) +{ + if (elt->data) + free(elt->data); + void_list_elt_deinit((void_list_elt_t *) elt); +} + +str_list_t *str_list_alloc() +{ + str_list_t *list = xcalloc(1, sizeof(str_list_t)); + str_list_init(list); + return list; +} + +void str_list_init(str_list_t *list) +{ + void_list_init((void_list_t *) list); +} + +void str_list_deinit(str_list_t *list) +{ + str_list_elt_t *elt; + while (!void_list_empty(list)) { + elt = str_list_first(list); + if (!elt) + return; + list_del_init(&elt->node); + free(elt->data); + elt->data=NULL; + free(elt); + } +} + +void str_list_append(str_list_t *list, char *data) +{ + void_list_append((void_list_t *) list, xstrdup(data)); +} + +void str_list_push(str_list_t *list, char *data) +{ + void_list_push((void_list_t *) list, xstrdup(data)); +} + +str_list_elt_t *str_list_pop(str_list_t *list) +{ + return (str_list_elt_t *) void_list_pop((void_list_t *) list); +} + +void str_list_remove(str_list_t *list, str_list_elt_t **iter) +{ + char *str = void_list_remove((void_list_t *) list, + (void_list_elt_t **) iter); + + if (str) + free(str); +} + +void str_list_remove_elt(str_list_t *list, const char *target_str) +{ + char *str = void_list_remove_elt((void_list_t *) list, + (void *)target_str, + (void_list_cmp_t)strcmp); + if (str) + free(str); +} + +str_list_elt_t *str_list_first(str_list_t *list) { + return (str_list_elt_t * )void_list_first((void_list_t *) list); +} + +str_list_elt_t *str_list_prev(str_list_t *list, str_list_elt_t *node) { + return (str_list_elt_t * )void_list_prev((void_list_t *) list, (void_list_elt_t *)node); +} + +str_list_elt_t *str_list_next(str_list_t *list, str_list_elt_t *node) { + return (str_list_elt_t * )void_list_next((void_list_t *) list, (void_list_elt_t *)node); +} + +str_list_elt_t *str_list_last(str_list_t *list) { + return (str_list_elt_t * )void_list_last((void_list_t *) list); +} + + +void str_list_purge(str_list_t *list) { + str_list_deinit(list); + free(list); +} diff --git a/src/libopkg/str_list.h b/src/libopkg/str_list.h new file mode 100644 index 0000000..3690820 --- /dev/null +++ b/src/libopkg/str_list.h @@ -0,0 +1,47 @@ +/* str_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef STR_LIST_H +#define STR_LIST_H + +#include "void_list.h" + +typedef struct void_list_elt str_list_elt_t; + +typedef struct void_list str_list_t; + +void str_list_elt_init(str_list_elt_t *elt, char *data); +void str_list_elt_deinit(str_list_elt_t *elt); + +str_list_t *str_list_alloc(void); +void str_list_init(str_list_t *list); +void str_list_deinit(str_list_t *list); + +void str_list_append(str_list_t *list, char *data); +void str_list_push(str_list_t *list, char *data); +str_list_elt_t *str_list_pop(str_list_t *list); +void str_list_remove(str_list_t *list, str_list_elt_t **iter); +void str_list_remove_elt(str_list_t *list, const char *target_str); + +str_list_elt_t *str_list_first(str_list_t *list); +str_list_elt_t *str_list_prev(str_list_t *list, str_list_elt_t *node); +str_list_elt_t *str_list_next(str_list_t *list, str_list_elt_t *node); +str_list_elt_t *str_list_last(str_list_t *list); + +void str_list_purge(str_list_t *list); + +#endif diff --git a/src/libopkg/void_list.c b/src/libopkg/void_list.c new file mode 100644 index 0000000..4c9d897 --- /dev/null +++ b/src/libopkg/void_list.c @@ -0,0 +1,165 @@ +/* void_list.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "void_list.h" +#include "libbb/libbb.h" + +void void_list_elt_init(void_list_elt_t *elt, void *data) +{ + INIT_LIST_HEAD(&elt->node); + elt->data = data; +} + +static void_list_elt_t * void_list_elt_new (void *data) { + void_list_elt_t *elt; + /* freed in void_list_elt_deinit */ + elt = xcalloc(1, sizeof(void_list_elt_t)); + void_list_elt_init(elt, data); + return elt; +} + +void void_list_elt_deinit(void_list_elt_t *elt) +{ + list_del_init(&elt->node); + void_list_elt_init(elt, NULL); + free(elt); +} + +void void_list_init(void_list_t *list) +{ + INIT_LIST_HEAD(&list->head); +} + +void void_list_deinit(void_list_t *list) +{ + void_list_elt_t *elt; + + while (!void_list_empty(list)) { + elt = void_list_pop(list); + void_list_elt_deinit(elt); + } + INIT_LIST_HEAD(&list->head); +} + +void void_list_append(void_list_t *list, void *data) +{ + void_list_elt_t *elt = void_list_elt_new(data); + list_add_tail(&elt->node, &list->head); +} + +void void_list_push(void_list_t *list, void *data) +{ + void_list_elt_t *elt = void_list_elt_new(data); + list_add(&elt->node, &list->head); +} + +void_list_elt_t *void_list_pop(void_list_t *list) +{ + struct list_head *node; + + if (void_list_empty(list)) + return NULL; + node = list->head.next; + list_del_init(node); + return list_entry(node, void_list_elt_t, node); +} + +void *void_list_remove(void_list_t *list, void_list_elt_t **iter) +{ + void_list_elt_t *pos, *n; + void_list_elt_t *old_elt; + void *old_data = NULL; + + old_elt = *iter; + if (!old_elt) + return old_data; + old_data = old_elt->data; + + list_for_each_entry_safe(pos, n, &list->head, node) { + if (pos == old_elt) + break; + } + if ( pos != old_elt) { + opkg_msg(ERROR, "Internal error: element not found in list.\n"); + return NULL; + } + + *iter = list_entry(pos->node.prev, void_list_elt_t, node); + void_list_elt_deinit(pos); + + return old_data; +} + +/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */ +void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp) +{ + void_list_elt_t *pos, *n; + void *old_data = NULL; + list_for_each_entry_safe(pos, n, &list->head, node) { + if ( pos->data && cmp(pos->data, target_data)==0 ){ + old_data = pos->data; + void_list_elt_deinit(pos); + break; + } + } + return old_data; +} + +void_list_elt_t *void_list_first(void_list_t *list) { + struct list_head *elt; + if (!list) + return NULL; + elt = list->head.next; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_prev(void_list_t *list, void_list_elt_t *node) { + struct list_head *elt; + if (!list || !node) + return NULL; + elt = node->node.prev; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_next(void_list_t *list, void_list_elt_t *node) { + struct list_head *elt; + if (!list || !node) + return NULL; + elt = node->node.next; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + +void_list_elt_t *void_list_last(void_list_t *list) { + struct list_head *elt; + if (!list) + return NULL; + elt = list->head.prev; + if (elt == &list->head ) { + return NULL; + } + return list_entry(elt, void_list_elt_t, node); +} + diff --git a/src/libopkg/void_list.h b/src/libopkg/void_list.h new file mode 100644 index 0000000..b63a68d --- /dev/null +++ b/src/libopkg/void_list.h @@ -0,0 +1,64 @@ +/* void_list.h - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef VOID_LIST_H +#define VOID_LIST_H + +#include "list.h" + +typedef struct void_list_elt void_list_elt_t; +struct void_list_elt +{ + struct list_head node; + void *data; +}; + +typedef struct void_list void_list_t; +struct void_list +{ + struct list_head head; +}; + +static inline int void_list_empty(void_list_t *list) +{ + return list_empty(&list->head); +} + +void void_list_elt_init(void_list_elt_t *elt, void *data); +void void_list_elt_deinit(void_list_elt_t *elt); + +void void_list_init(void_list_t *list); +void void_list_deinit(void_list_t *list); + +void void_list_append(void_list_t *list, void *data); +void void_list_push(void_list_t *list, void *data); +void_list_elt_t *void_list_pop(void_list_t *list); + +void *void_list_remove(void_list_t *list, void_list_elt_t **iter); +/* remove element containing elt data, using cmp(elt->data, target_data) == 0. */ +typedef int (*void_list_cmp_t)(const void *, const void *); +void *void_list_remove_elt(void_list_t *list, const void *target_data, void_list_cmp_t cmp); + +void_list_elt_t *void_list_first(void_list_t *list); +void_list_elt_t *void_list_prev(void_list_t *list, void_list_elt_t *node); +void_list_elt_t *void_list_next(void_list_t *list, void_list_elt_t *node); +void_list_elt_t *void_list_last(void_list_t *list); + +void void_list_purge(void_list_t *list); + + +#endif diff --git a/src/libopkg/xregex.c b/src/libopkg/xregex.c new file mode 100644 index 0000000..f682d4c --- /dev/null +++ b/src/libopkg/xregex.c @@ -0,0 +1,46 @@ +/* xregex.c - regex functions with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include "xregex.h" +#include "libbb/libbb.h" + +static void print_regcomp_err(const regex_t *preg, int err); + +int xregcomp(regex_t *preg, const char *regex, int cflags) +{ + int err; + err = regcomp(preg, regex, cflags); + if (err) { + print_regcomp_err(preg, err); + } + + return err; +} + +static void print_regcomp_err(const regex_t *preg, int err) +{ + unsigned int size; + char *error; + + size = regerror(err, preg, 0, 0); + error = xcalloc(1, size); + regerror(err, preg, error, size); + + opkg_msg(ERROR, "Internal error compiling regex: %s.", error); + + free(error); +} diff --git a/src/libopkg/xregex.h b/src/libopkg/xregex.h new file mode 100644 index 0000000..f67572b --- /dev/null +++ b/src/libopkg/xregex.h @@ -0,0 +1,31 @@ +/* xregex.h - regex functions with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef XREGEX_H +#define XREGEX_H + +#include <sys/types.h> +#include <regex.h> + +int xregcomp(regex_t *preg, const char *regex, int cflags); +static inline void xregfree(regex_t *preg) +{ + regfree(preg); +} + + +#endif diff --git a/src/libopkg/xsystem.c b/src/libopkg/xsystem.c new file mode 100644 index 0000000..ae7ca87 --- /dev/null +++ b/src/libopkg/xsystem.c @@ -0,0 +1,73 @@ +/* xsystem.c - system(3) with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "xsystem.h" +#include "libbb/libbb.h" + +/* Like system(3), but with error messages printed if the fork fails + or if the child process dies due to an uncaught signal. Also, the + return value is a bit simpler: + + -1 if there was any problem + Otherwise, the 8-bit return value of the program ala WEXITSTATUS + as defined in <sys/wait.h>. +*/ +int +xsystem(const char *argv[]) +{ + int status; + pid_t pid; + + pid = vfork(); + + switch (pid) { + case -1: + opkg_perror(ERROR, "%s: vfork", argv[0]); + return -1; + case 0: + /* child */ + execvp(argv[0], (char*const*)argv); + _exit(-1); + default: + /* parent */ + break; + } + + if (waitpid(pid, &status, 0) == -1) { + opkg_perror(ERROR, "%s: waitpid", argv[0]); + return -1; + } + + if (WIFSIGNALED(status)) { + opkg_msg(ERROR, "%s: Child killed by signal %d.\n", + argv[0], WTERMSIG(status)); + return -1; + } + + if (!WIFEXITED(status)) { + /* shouldn't happen */ + opkg_msg(ERROR, "%s: Your system is broken: got status %d " + "from waitpid.\n", argv[0], status); + return -1; + } + + return WEXITSTATUS(status); +} diff --git a/src/libopkg/xsystem.h b/src/libopkg/xsystem.h new file mode 100644 index 0000000..042efad --- /dev/null +++ b/src/libopkg/xsystem.h @@ -0,0 +1,32 @@ +/* xsystem.h - system(3) with error messages + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + + 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, 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. +*/ + +#ifndef XSYSTEM_H +#define XSYSTEM_H + +/* Like system(3), but with error messages printed if the fork fails + or if the child process dies due to an uncaught signal. Also, the + return value is a bit simpler: + + -1 if there was any problem + Otherwise, the 8-bit return value of the program ala WEXITSTATUS + as defined in <sys/wait.h>. +*/ +int xsystem(const char *argv[]); + +#endif + |