summaryrefslogtreecommitdiffstats
path: root/src/libopkg
diff options
context:
space:
mode:
authorP. J. McDermott <pjm@nac.net>2012-02-09 10:56:43 (EST)
committer P. J. McDermott <pjm@nac.net>2012-02-09 10:56:43 (EST)
commitf431cd1a48a6a5186633bf5f16a2d21cb4399e8c (patch)
tree337e36fd9d7884fcf76ba769ab7b0039f52d9d31 /src/libopkg
Initial commit.
TODO: Copyright information. Including source code and a patch to add files generated by GNU Autoconf is not very pretty... Running 'make dist' in the SVN trunk to generate a source archive might be better.
Diffstat (limited to 'src/libopkg')
-rw-r--r--src/libopkg/.svn/all-wcprops491
-rw-r--r--src/libopkg/.svn/entries2782
-rw-r--r--src/libopkg/.svn/text-base/Makefile.am.svn-base55
-rw-r--r--src/libopkg/.svn/text-base/active_list.c.svn-base165
-rw-r--r--src/libopkg/.svn/text-base/active_list.h.svn-base44
-rw-r--r--src/libopkg/.svn/text-base/cksum_list.c.svn-base87
-rw-r--r--src/libopkg/.svn/text-base/cksum_list.h.svn-base46
-rw-r--r--src/libopkg/.svn/text-base/conffile.c.svn-base63
-rw-r--r--src/libopkg/.svn/text-base/conffile.h.svn-base29
-rw-r--r--src/libopkg/.svn/text-base/conffile_list.c.svn-base46
-rw-r--r--src/libopkg/.svn/text-base/conffile_list.h.svn-base37
-rw-r--r--src/libopkg/.svn/text-base/file_util.c.svn-base315
-rw-r--r--src/libopkg/.svn/text-base/file_util.h.svn-base31
-rw-r--r--src/libopkg/.svn/text-base/hash_table.c.svn-base215
-rw-r--r--src/libopkg/.svn/text-base/hash_table.h.svn-base51
-rw-r--r--src/libopkg/.svn/text-base/list.h.svn-base304
-rw-r--r--src/libopkg/.svn/text-base/md5.c.svn-base455
-rw-r--r--src/libopkg/.svn/text-base/md5.h.svn-base118
-rw-r--r--src/libopkg/.svn/text-base/nv_pair.c.svn-base39
-rw-r--r--src/libopkg/.svn/text-base/nv_pair.h.svn-base32
-rw-r--r--src/libopkg/.svn/text-base/nv_pair_list.c.svn-base98
-rw-r--r--src/libopkg/.svn/text-base/nv_pair_list.h.svn-base48
-rw-r--r--src/libopkg/.svn/text-base/opkg.c.svn-base872
-rw-r--r--src/libopkg/.svn/text-base/opkg.h.svn-base61
-rw-r--r--src/libopkg/.svn/text-base/opkg_cmd.c.svn-base1319
-rw-r--r--src/libopkg/.svn/text-base/opkg_cmd.h.svn-base36
-rw-r--r--src/libopkg/.svn/text-base/opkg_conf.c.svn-base688
-rw-r--r--src/libopkg/.svn/text-base/opkg_conf.h.svn-base145
-rw-r--r--src/libopkg/.svn/text-base/opkg_configure.c.svn-base44
-rw-r--r--src/libopkg/.svn/text-base/opkg_configure.h.svn-base25
-rw-r--r--src/libopkg/.svn/text-base/opkg_defines.h.svn-base35
-rw-r--r--src/libopkg/.svn/text-base/opkg_download.c.svn-base679
-rw-r--r--src/libopkg/.svn/text-base/opkg_download.h.svn-base39
-rw-r--r--src/libopkg/.svn/text-base/opkg_install.c.svn-base1528
-rw-r--r--src/libopkg/.svn/text-base/opkg_install.h.svn-base27
-rw-r--r--src/libopkg/.svn/text-base/opkg_message.c.svn-base121
-rw-r--r--src/libopkg/.svn/text-base/opkg_message.h.svn-base47
-rw-r--r--src/libopkg/.svn/text-base/opkg_pathfinder.c.svn-base100
-rw-r--r--src/libopkg/.svn/text-base/opkg_pathfinder.h.svn-base31
-rw-r--r--src/libopkg/.svn/text-base/opkg_remove.c.svn-base450
-rw-r--r--src/libopkg/.svn/text-base/opkg_remove.h.svn-base30
-rw-r--r--src/libopkg/.svn/text-base/opkg_upgrade.c.svn-base130
-rw-r--r--src/libopkg/.svn/text-base/opkg_upgrade.h.svn-base22
-rw-r--r--src/libopkg/.svn/text-base/opkg_utils.c.svn-base78
-rw-r--r--src/libopkg/.svn/text-base/opkg_utils.h.svn-base25
-rw-r--r--src/libopkg/.svn/text-base/parse_util.c.svn-base168
-rw-r--r--src/libopkg/.svn/text-base/parse_util.h.svn-base31
-rw-r--r--src/libopkg/.svn/text-base/pkg.c.svn-base1428
-rw-r--r--src/libopkg/.svn/text-base/pkg.h.svn-base231
-rw-r--r--src/libopkg/.svn/text-base/pkg_depends.c.svn-base931
-rw-r--r--src/libopkg/.svn/text-base/pkg_depends.h.svn-base90
-rw-r--r--src/libopkg/.svn/text-base/pkg_dest.c.svn-base82
-rw-r--r--src/libopkg/.svn/text-base/pkg_dest.h.svn-base39
-rw-r--r--src/libopkg/.svn/text-base/pkg_dest_list.c.svn-base77
-rw-r--r--src/libopkg/.svn/text-base/pkg_dest_list.h.svn-base39
-rw-r--r--src/libopkg/.svn/text-base/pkg_extract.c.svn-base99
-rw-r--r--src/libopkg/.svn/text-base/pkg_extract.h.svn-base31
-rw-r--r--src/libopkg/.svn/text-base/pkg_hash.c.svn-base735
-rw-r--r--src/libopkg/.svn/text-base/pkg_hash.h.svn-base56
-rw-r--r--src/libopkg/.svn/text-base/pkg_parse.c.svn-base285
-rw-r--r--src/libopkg/.svn/text-base/pkg_parse.h.svn-base57
-rw-r--r--src/libopkg/.svn/text-base/pkg_src.c.svn-base39
-rw-r--r--src/libopkg/.svn/text-base/pkg_src.h.svn-base34
-rw-r--r--src/libopkg/.svn/text-base/pkg_src_list.c.svn-base64
-rw-r--r--src/libopkg/.svn/text-base/pkg_src_list.h.svn-base44
-rw-r--r--src/libopkg/.svn/text-base/pkg_vec.c.svn-base208
-rw-r--r--src/libopkg/.svn/text-base/pkg_vec.h.svn-base63
-rw-r--r--src/libopkg/.svn/text-base/release.c.svn-base342
-rw-r--r--src/libopkg/.svn/text-base/release.h.svn-base53
-rw-r--r--src/libopkg/.svn/text-base/release_parse.c.svn-base126
-rw-r--r--src/libopkg/.svn/text-base/release_parse.h.svn-base21
-rw-r--r--src/libopkg/.svn/text-base/sha256.c.svn-base554
-rw-r--r--src/libopkg/.svn/text-base/sha256.h.svn-base91
-rw-r--r--src/libopkg/.svn/text-base/sprintf_alloc.c.svn-base49
-rw-r--r--src/libopkg/.svn/text-base/sprintf_alloc.h.svn-base23
-rw-r--r--src/libopkg/.svn/text-base/str_list.c.svn-base112
-rw-r--r--src/libopkg/.svn/text-base/str_list.h.svn-base47
-rw-r--r--src/libopkg/.svn/text-base/void_list.c.svn-base165
-rw-r--r--src/libopkg/.svn/text-base/void_list.h.svn-base64
-rw-r--r--src/libopkg/.svn/text-base/xregex.c.svn-base46
-rw-r--r--src/libopkg/.svn/text-base/xregex.h.svn-base31
-rw-r--r--src/libopkg/.svn/text-base/xsystem.c.svn-base73
-rw-r--r--src/libopkg/.svn/text-base/xsystem.h.svn-base32
-rw-r--r--src/libopkg/Makefile.am55
-rw-r--r--src/libopkg/active_list.c165
-rw-r--r--src/libopkg/active_list.h44
-rw-r--r--src/libopkg/cksum_list.c87
-rw-r--r--src/libopkg/cksum_list.h46
-rw-r--r--src/libopkg/conffile.c63
-rw-r--r--src/libopkg/conffile.h29
-rw-r--r--src/libopkg/conffile_list.c46
-rw-r--r--src/libopkg/conffile_list.h37
-rw-r--r--src/libopkg/file_util.c315
-rw-r--r--src/libopkg/file_util.h31
-rw-r--r--src/libopkg/hash_table.c215
-rw-r--r--src/libopkg/hash_table.h51
-rw-r--r--src/libopkg/list.h304
-rw-r--r--src/libopkg/md5.c455
-rw-r--r--src/libopkg/md5.h118
-rw-r--r--src/libopkg/nv_pair.c39
-rw-r--r--src/libopkg/nv_pair.h32
-rw-r--r--src/libopkg/nv_pair_list.c98
-rw-r--r--src/libopkg/nv_pair_list.h48
-rw-r--r--src/libopkg/opkg.c872
-rw-r--r--src/libopkg/opkg.h61
-rw-r--r--src/libopkg/opkg_cmd.c1319
-rw-r--r--src/libopkg/opkg_cmd.h36
-rw-r--r--src/libopkg/opkg_conf.c688
-rw-r--r--src/libopkg/opkg_conf.h145
-rw-r--r--src/libopkg/opkg_configure.c44
-rw-r--r--src/libopkg/opkg_configure.h25
-rw-r--r--src/libopkg/opkg_defines.h35
-rw-r--r--src/libopkg/opkg_download.c679
-rw-r--r--src/libopkg/opkg_download.h39
-rw-r--r--src/libopkg/opkg_install.c1528
-rw-r--r--src/libopkg/opkg_install.h27
-rw-r--r--src/libopkg/opkg_message.c121
-rw-r--r--src/libopkg/opkg_message.h47
-rw-r--r--src/libopkg/opkg_pathfinder.c100
-rw-r--r--src/libopkg/opkg_pathfinder.h31
-rw-r--r--src/libopkg/opkg_remove.c450
-rw-r--r--src/libopkg/opkg_remove.h30
-rw-r--r--src/libopkg/opkg_upgrade.c130
-rw-r--r--src/libopkg/opkg_upgrade.h22
-rw-r--r--src/libopkg/opkg_utils.c78
-rw-r--r--src/libopkg/opkg_utils.h25
-rw-r--r--src/libopkg/parse_util.c168
-rw-r--r--src/libopkg/parse_util.h31
-rw-r--r--src/libopkg/pkg.c1428
-rw-r--r--src/libopkg/pkg.h231
-rw-r--r--src/libopkg/pkg_depends.c931
-rw-r--r--src/libopkg/pkg_depends.h90
-rw-r--r--src/libopkg/pkg_dest.c82
-rw-r--r--src/libopkg/pkg_dest.h39
-rw-r--r--src/libopkg/pkg_dest_list.c77
-rw-r--r--src/libopkg/pkg_dest_list.h39
-rw-r--r--src/libopkg/pkg_extract.c99
-rw-r--r--src/libopkg/pkg_extract.h31
-rw-r--r--src/libopkg/pkg_hash.c735
-rw-r--r--src/libopkg/pkg_hash.h56
-rw-r--r--src/libopkg/pkg_parse.c285
-rw-r--r--src/libopkg/pkg_parse.h57
-rw-r--r--src/libopkg/pkg_src.c39
-rw-r--r--src/libopkg/pkg_src.h34
-rw-r--r--src/libopkg/pkg_src_list.c64
-rw-r--r--src/libopkg/pkg_src_list.h44
-rw-r--r--src/libopkg/pkg_vec.c208
-rw-r--r--src/libopkg/pkg_vec.h63
-rw-r--r--src/libopkg/release.c342
-rw-r--r--src/libopkg/release.h53
-rw-r--r--src/libopkg/release_parse.c126
-rw-r--r--src/libopkg/release_parse.h21
-rw-r--r--src/libopkg/sha256.c554
-rw-r--r--src/libopkg/sha256.h91
-rw-r--r--src/libopkg/sprintf_alloc.c49
-rw-r--r--src/libopkg/sprintf_alloc.h23
-rw-r--r--src/libopkg/str_list.c112
-rw-r--r--src/libopkg/str_list.h47
-rw-r--r--src/libopkg/void_list.c165
-rw-r--r--src/libopkg/void_list.h64
-rw-r--r--src/libopkg/xregex.c46
-rw-r--r--src/libopkg/xregex.h31
-rw-r--r--src/libopkg/xsystem.c73
-rw-r--r--src/libopkg/xsystem.h32
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
+