summaryrefslogtreecommitdiffstats
path: root/src
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
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')
-rw-r--r--src/.gitignore66
-rw-r--r--src/.svn/all-wcprops89
-rw-r--r--src/.svn/entries534
-rw-r--r--src/.svn/prop-base/autogen.sh.svn-base5
-rw-r--r--src/.svn/text-base/.gitignore.svn-base66
-rw-r--r--src/.svn/text-base/AUTHORS.svn-base8
-rw-r--r--src/.svn/text-base/CONTRIBUTORS.svn-base31
-rw-r--r--src/.svn/text-base/COPYING.svn-base340
-rw-r--r--src/.svn/text-base/ChangeLog.ipkg.svn-base1761
-rw-r--r--src/.svn/text-base/ChangeLog.svn-base1
-rw-r--r--src/.svn/text-base/INSTALL.svn-base196
-rw-r--r--src/.svn/text-base/Makefile.am.svn-base37
-rw-r--r--src/.svn/text-base/NEWS.svn-base0
-rw-r--r--src/.svn/text-base/README.svn-base12
-rw-r--r--src/.svn/text-base/TODO.svn-base42
-rw-r--r--src/.svn/text-base/autogen.sh.svn-base5
-rw-r--r--src/.svn/text-base/configure.ac.svn-base297
-rw-r--r--src/.svn/text-base/libopkg.pc.in.svn-base11
-rw-r--r--src/AUTHORS8
-rw-r--r--src/CONTRIBUTORS31
-rw-r--r--src/COPYING340
-rw-r--r--src/ChangeLog1
-rw-r--r--src/ChangeLog.ipkg1761
-rw-r--r--src/INSTALL196
-rw-r--r--src/Makefile.am37
-rw-r--r--src/NEWS0
-rw-r--r--src/README12
-rw-r--r--src/TODO42
-rwxr-xr-xsrc/autogen.sh5
-rw-r--r--src/configure.ac297
-rw-r--r--src/etc/.svn/all-wcprops5
-rw-r--r--src/etc/.svn/entries28
-rw-r--r--src/familiar/.svn/all-wcprops5
-rw-r--r--src/familiar/.svn/entries28
-rw-r--r--src/intercept/.svn/all-wcprops23
-rw-r--r--src/intercept/.svn/entries130
-rw-r--r--src/intercept/.svn/text-base/depmod.svn-base12
-rw-r--r--src/intercept/.svn/text-base/ldconfig.svn-base7
-rw-r--r--src/intercept/.svn/text-base/update-modules.svn-base7
-rw-r--r--src/intercept/depmod12
-rw-r--r--src/intercept/ldconfig7
-rw-r--r--src/intercept/update-modules7
-rw-r--r--src/libbb/.svn/all-wcprops113
-rw-r--r--src/libbb/.svn/entries640
-rw-r--r--src/libbb/.svn/text-base/Makefile.am.svn-base26
-rw-r--r--src/libbb/.svn/text-base/all_read.c.svn-base83
-rw-r--r--src/libbb/.svn/text-base/concat_path_file.c.svn-base45
-rw-r--r--src/libbb/.svn/text-base/copy_file.c.svn-base231
-rw-r--r--src/libbb/.svn/text-base/copy_file_chunk.c.svn-base70
-rw-r--r--src/libbb/.svn/text-base/gz_open.c.svn-base149
-rw-r--r--src/libbb/.svn/text-base/last_char_is.c.svn-base40
-rw-r--r--src/libbb/.svn/text-base/libbb.h.svn-base123
-rw-r--r--src/libbb/.svn/text-base/make_directory.c.svn-base80
-rw-r--r--src/libbb/.svn/text-base/mode_string.c.svn-base78
-rw-r--r--src/libbb/.svn/text-base/parse_mode.c.svn-base134
-rw-r--r--src/libbb/.svn/text-base/safe_strncpy.c.svn-base42
-rw-r--r--src/libbb/.svn/text-base/time_string.c.svn-base62
-rw-r--r--src/libbb/.svn/text-base/unarchive.c.svn-base784
-rw-r--r--src/libbb/.svn/text-base/unzip.c.svn-base1021
-rw-r--r--src/libbb/.svn/text-base/wfopen.c.svn-base44
-rw-r--r--src/libbb/.svn/text-base/xfuncs.c.svn-base93
-rw-r--r--src/libbb/.svn/text-base/xreadlink.c.svn-base37
-rw-r--r--src/libbb/Makefile.am26
-rw-r--r--src/libbb/all_read.c83
-rw-r--r--src/libbb/concat_path_file.c45
-rw-r--r--src/libbb/copy_file.c231
-rw-r--r--src/libbb/copy_file_chunk.c70
-rw-r--r--src/libbb/gz_open.c149
-rw-r--r--src/libbb/last_char_is.c40
-rw-r--r--src/libbb/libbb.h123
-rw-r--r--src/libbb/make_directory.c80
-rw-r--r--src/libbb/mode_string.c78
-rw-r--r--src/libbb/parse_mode.c134
-rw-r--r--src/libbb/safe_strncpy.c42
-rw-r--r--src/libbb/time_string.c62
-rw-r--r--src/libbb/unarchive.c784
-rw-r--r--src/libbb/unzip.c1021
-rw-r--r--src/libbb/wfopen.c44
-rw-r--r--src/libbb/xfuncs.c93
-rw-r--r--src/libbb/xreadlink.c37
-rw-r--r--src/libopkg.pc.in11
-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
-rw-r--r--src/man/.svn/all-wcprops23
-rw-r--r--src/man/.svn/entries130
-rw-r--r--src/man/.svn/text-base/Makefile.am.svn-base2
-rw-r--r--src/man/.svn/text-base/opkg-cl.1.in.svn-base190
-rw-r--r--src/man/.svn/text-base/opkg-key.1.in.svn-base37
-rw-r--r--src/man/Makefile.am2
-rw-r--r--src/man/opkg-cl.1.in190
-rw-r--r--src/man/opkg-key.1.in37
-rw-r--r--src/shave/.svn/all-wcprops23
-rw-r--r--src/shave/.svn/entries130
-rw-r--r--src/shave/.svn/text-base/shave-libtool.in.svn-base69
-rw-r--r--src/shave/.svn/text-base/shave.in.svn-base79
-rw-r--r--src/shave/.svn/text-base/shave.m4.svn-base77
-rw-r--r--src/shave/shave-libtool.in69
-rw-r--r--src/shave/shave.in79
-rw-r--r--src/shave/shave.m477
-rw-r--r--src/src/.svn/all-wcprops17
-rw-r--r--src/src/.svn/entries96
-rw-r--r--src/src/.svn/text-base/Makefile.am.svn-base6
-rw-r--r--src/src/.svn/text-base/opkg-cl.c.svn-base390
-rw-r--r--src/src/Makefile.am6
-rw-r--r--src/src/opkg-cl.c390
-rw-r--r--src/tests/.svn/all-wcprops35
-rw-r--r--src/tests/.svn/entries201
-rw-r--r--src/tests/.svn/text-base/Makefile.am.svn-base23
-rw-r--r--src/tests/.svn/text-base/libopkg_test.c.svn-base261
-rw-r--r--src/tests/.svn/text-base/opkg_active_list_test.c.svn-base145
-rw-r--r--src/tests/.svn/text-base/opkg_extract_test.c.svn-base46
-rw-r--r--src/tests/.svn/text-base/opkg_hash_test.c.svn-base79
-rw-r--r--src/tests/Makefile.am23
-rw-r--r--src/tests/libopkg_test.c261
-rw-r--r--src/tests/opkg_active_list_test.c145
-rw-r--r--src/tests/opkg_extract_test.c46
-rw-r--r--src/tests/opkg_hash_test.c79
-rw-r--r--src/tests/regress/.svn/all-wcprops113
-rw-r--r--src/tests/regress/.svn/entries640
-rw-r--r--src/tests/regress/.svn/prop-base/filehash.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue26.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue31.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue45.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue46.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue50.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue51.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue55.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue58.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue72.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue79.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue84.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/issue85.py.svn-base5
-rw-r--r--src/tests/regress/.svn/prop-base/opkgcl.py.svn-base5
-rw-r--r--src/tests/regress/.svn/text-base/Makefile.svn-base15
-rw-r--r--src/tests/regress/.svn/text-base/cfg.py.svn-base5
-rw-r--r--src/tests/regress/.svn/text-base/filehash.py.svn-base35
-rw-r--r--src/tests/regress/.svn/text-base/issue26.py.svn-base35
-rw-r--r--src/tests/regress/.svn/text-base/issue31.py.svn-base25
-rw-r--r--src/tests/regress/.svn/text-base/issue45.py.svn-base33
-rw-r--r--src/tests/regress/.svn/text-base/issue46.py.svn-base39
-rw-r--r--src/tests/regress/.svn/text-base/issue50.py.svn-base43
-rw-r--r--src/tests/regress/.svn/text-base/issue51.py.svn-base70
-rw-r--r--src/tests/regress/.svn/text-base/issue55.py.svn-base25
-rw-r--r--src/tests/regress/.svn/text-base/issue58.py.svn-base31
-rw-r--r--src/tests/regress/.svn/text-base/issue72.py.svn-base52
-rw-r--r--src/tests/regress/.svn/text-base/issue79.py.svn-base33
-rw-r--r--src/tests/regress/.svn/text-base/issue84.py.svn-base45
-rw-r--r--src/tests/regress/.svn/text-base/issue85.py.svn-base29
-rw-r--r--src/tests/regress/.svn/text-base/opk.py.svn-base111
-rw-r--r--src/tests/regress/.svn/text-base/opkgcl.py.svn-base64
-rw-r--r--src/tests/regress/.svn/text-base/update_loses_autoinstalled_flag.py.svn-base63
-rw-r--r--src/tests/regress/Makefile15
-rw-r--r--src/tests/regress/cfg.py5
-rwxr-xr-xsrc/tests/regress/filehash.py35
-rwxr-xr-xsrc/tests/regress/issue26.py35
-rwxr-xr-xsrc/tests/regress/issue31.py25
-rwxr-xr-xsrc/tests/regress/issue45.py33
-rwxr-xr-xsrc/tests/regress/issue46.py39
-rwxr-xr-xsrc/tests/regress/issue50.py43
-rwxr-xr-xsrc/tests/regress/issue51.py70
-rwxr-xr-xsrc/tests/regress/issue55.py25
-rwxr-xr-xsrc/tests/regress/issue58.py31
-rwxr-xr-xsrc/tests/regress/issue72.py52
-rwxr-xr-xsrc/tests/regress/issue79.py33
-rwxr-xr-xsrc/tests/regress/issue84.py45
-rwxr-xr-xsrc/tests/regress/issue85.py29
-rw-r--r--src/tests/regress/opk.py111
-rwxr-xr-xsrc/tests/regress/opkgcl.py64
-rw-r--r--src/tests/regress/update_loses_autoinstalled_flag.py63
-rw-r--r--src/utils/.svn/all-wcprops23
-rw-r--r--src/utils/.svn/entries130
-rw-r--r--src/utils/.svn/prop-base/opkg-key.svn-base5
-rw-r--r--src/utils/.svn/text-base/Makefile.am.svn-base3
-rw-r--r--src/utils/.svn/text-base/opkg-key.svn-base74
-rw-r--r--src/utils/.svn/text-base/update-alternatives.in.svn-base197
-rw-r--r--src/utils/Makefile.am3
-rwxr-xr-xsrc/utils/opkg-key74
-rw-r--r--src/utils/update-alternatives.in197
340 files changed, 54261 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..df61d46
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,66 @@
+# git-ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+
+*.orig
+*.rej
+*.mergebackup
+*.[oa]
+*~
+*.*.swp
+
+Makefile
+Makefile.in
+# o_0
+Makefile.in.in
+!tests/regress/Makefile
+
+# The local aclocal.m4 file
+aclocal.m4
+m4/
+shave/lt*
+shave/libtool.m4
+shave/shave
+shave/shave-libtool
+
+# The output of the configure script
+conf/
+config.guess
+config.log
+config.status
+config.sub
+
+# The configure script itself
+configure
+
+# The libopkg directory artifacts
+libopkg/config.h
+libopkg/config.h.in
+libopkg/stamp-h1
+
+# Various scripts used for libtool and the like
+install-sh
+libtool
+ltmain.sh
+missing
+depcomp
+
+# opkg stuff
+libopkg.pc
+utils/update-alternatives
+
+autom4te.cache/
+
+# Binaries
+*.la
+*.lo
+*.o
+*.so
+.libs/
+.deps/
+src/opkg-cl
+tests/libopkg_test
+
+# Man pages
+man/*.1
diff --git a/src/.svn/all-wcprops b/src/.svn/all-wcprops
new file mode 100644
index 0000000..d17ce1b
--- /dev/null
+++ b/src/.svn/all-wcprops
@@ -0,0 +1,89 @@
+K 25
+svn:wc:ra_dav:version-url
+V 23
+/svn/!svn/ver/635/trunk
+END
+ChangeLog.ipkg
+K 25
+svn:wc:ra_dav:version-url
+V 37
+/svn/!svn/ver/45/trunk/ChangeLog.ipkg
+END
+configure.ac
+K 25
+svn:wc:ra_dav:version-url
+V 36
+/svn/!svn/ver/569/trunk/configure.ac
+END
+AUTHORS
+K 25
+svn:wc:ra_dav:version-url
+V 31
+/svn/!svn/ver/367/trunk/AUTHORS
+END
+.gitignore
+K 25
+svn:wc:ra_dav:version-url
+V 34
+/svn/!svn/ver/592/trunk/.gitignore
+END
+TODO
+K 25
+svn:wc:ra_dav:version-url
+V 28
+/svn/!svn/ver/546/trunk/TODO
+END
+INSTALL
+K 25
+svn:wc:ra_dav:version-url
+V 29
+/svn/!svn/ver/8/trunk/INSTALL
+END
+ChangeLog
+K 25
+svn:wc:ra_dav:version-url
+V 33
+/svn/!svn/ver/152/trunk/ChangeLog
+END
+COPYING
+K 25
+svn:wc:ra_dav:version-url
+V 29
+/svn/!svn/ver/3/trunk/COPYING
+END
+Makefile.am
+K 25
+svn:wc:ra_dav:version-url
+V 35
+/svn/!svn/ver/548/trunk/Makefile.am
+END
+autogen.sh
+K 25
+svn:wc:ra_dav:version-url
+V 34
+/svn/!svn/ver/152/trunk/autogen.sh
+END
+NEWS
+K 25
+svn:wc:ra_dav:version-url
+V 26
+/svn/!svn/ver/3/trunk/NEWS
+END
+README
+K 25
+svn:wc:ra_dav:version-url
+V 30
+/svn/!svn/ver/367/trunk/README
+END
+libopkg.pc.in
+K 25
+svn:wc:ra_dav:version-url
+V 35
+/svn/!svn/ver/8/trunk/libopkg.pc.in
+END
+CONTRIBUTORS
+K 25
+svn:wc:ra_dav:version-url
+V 36
+/svn/!svn/ver/376/trunk/CONTRIBUTORS
+END
diff --git a/src/.svn/entries b/src/.svn/entries
new file mode 100644
index 0000000..b333909
--- /dev/null
+++ b/src/.svn/entries
@@ -0,0 +1,534 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk
+http://opkg.googlecode.com/svn
+
+
+
+2012-01-19T13:52:06.380812Z
+635
+pixdamix@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
+ChangeLog.ipkg
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+064c3f50dd01eee4cb2dc46d8055f6f6
+2008-12-15T04:52:44.191127Z
+45
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+78582
+
+familiar
+dir
+
+AUTHORS
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+0272ec7c17a60c808dc4a0c169a7361c
+2009-11-25T01:41:01.609303Z
+367
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+243
+
+ChangeLog
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+1ea0f9fbb3cede7f1c5114c52fd365d6
+2008-12-15T05:28:19.065585Z
+152
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+22
+
+src
+dir
+
+libopkg
+dir
+
+libopkg.pc.in
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+f982e631515033e25ff8c9a09b4925c3
+2008-12-15T04:18:06.332473Z
+8
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+227
+
+README
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+7e8175845a4449323e98c5ba04c112be
+2009-11-25T01:41:01.609303Z
+367
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+359
+
+intercept
+dir
+
+CONTRIBUTORS
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+e13dab17e320b26853e94e760afcdd45
+2009-11-25T22:21:24.495133Z
+376
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+901
+
+utils
+dir
+
+tests
+dir
+
+configure.ac
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+4f69827bb87e712814677914bc6e7adf
+2010-09-20T23:56:11.359263Z
+569
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8592
+
+.gitignore
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+5261d61d0b14306ed8813c34ccb50470
+2010-12-23T01:37:42.092726Z
+592
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+924
+
+TODO
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+822c3d787ef9e00758bd68ab3204a1b3
+2010-08-10T05:38:10.924792Z
+546
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1106
+
+shave
+dir
+
+INSTALL
+file
+
+
+
+
+2012-02-03T08:11:57.583042Z
+c29710d9db7eb38b63b6c6b191f4b4d8
+2008-12-15T04:18:06.332473Z
+8
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8204
+
+COPYING
+file
+
+
+
+
+2012-02-03T08:11:57.583042Z
+94d55d512a9ba36caa9b7df079bae19f
+2008-12-15T04:10:56.746937Z
+3
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+17992
+
+Makefile.am
+file
+
+
+
+
+2012-02-03T08:11:57.583042Z
+76cf3751c643dff1513f229641941123
+2010-08-10T05:38:37.144135Z
+548
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+869
+
+libbb
+dir
+
+etc
+dir
+
+man
+dir
+
+autogen.sh
+file
+
+
+
+
+2012-02-03T08:11:57.583042Z
+3d9595d846fb5d1a42d3cc20297bb3d9
+2008-12-15T05:28:19.065585Z
+152
+ticktock35
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+104
+
+NEWS
+file
+
+
+
+
+2012-02-03T08:11:57.583042Z
+d41d8cd98f00b204e9800998ecf8427e
+2008-12-15T04:10:56.746937Z
+3
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+0
+
diff --git a/src/.svn/prop-base/autogen.sh.svn-base b/src/.svn/prop-base/autogen.sh.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/.svn/prop-base/autogen.sh.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/.svn/text-base/.gitignore.svn-base b/src/.svn/text-base/.gitignore.svn-base
new file mode 100644
index 0000000..df61d46
--- /dev/null
+++ b/src/.svn/text-base/.gitignore.svn-base
@@ -0,0 +1,66 @@
+# git-ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+
+*.orig
+*.rej
+*.mergebackup
+*.[oa]
+*~
+*.*.swp
+
+Makefile
+Makefile.in
+# o_0
+Makefile.in.in
+!tests/regress/Makefile
+
+# The local aclocal.m4 file
+aclocal.m4
+m4/
+shave/lt*
+shave/libtool.m4
+shave/shave
+shave/shave-libtool
+
+# The output of the configure script
+conf/
+config.guess
+config.log
+config.status
+config.sub
+
+# The configure script itself
+configure
+
+# The libopkg directory artifacts
+libopkg/config.h
+libopkg/config.h.in
+libopkg/stamp-h1
+
+# Various scripts used for libtool and the like
+install-sh
+libtool
+ltmain.sh
+missing
+depcomp
+
+# opkg stuff
+libopkg.pc
+utils/update-alternatives
+
+autom4te.cache/
+
+# Binaries
+*.la
+*.lo
+*.o
+*.so
+.libs/
+.deps/
+src/opkg-cl
+tests/libopkg_test
+
+# Man pages
+man/*.1
diff --git a/src/.svn/text-base/AUTHORS.svn-base b/src/.svn/text-base/AUTHORS.svn-base
new file mode 100644
index 0000000..e7ce307
--- /dev/null
+++ b/src/.svn/text-base/AUTHORS.svn-base
@@ -0,0 +1,8 @@
+Opkg:
+ * Thomas Wood <thomas@openedhand.com>
+ * Tick Chen <ticktock35@gmail.com>
+ * Graham Gower <graham.gower@gmail.com>
+Ipkg:
+ * Pierluigi Frullani <pigi@frumar.it>
+ * Carl Worth <cworth@handhelds.org>
+ * Steve Ayer <steven.ayer@compaq.com>
diff --git a/src/.svn/text-base/CONTRIBUTORS.svn-base b/src/.svn/text-base/CONTRIBUTORS.svn-base
new file mode 100644
index 0000000..d85411a
--- /dev/null
+++ b/src/.svn/text-base/CONTRIBUTORS.svn-base
@@ -0,0 +1,31 @@
+=== Contributors ===
+
+The following people have submitted changes which have been applied to the
+core:
+
+Christopher Hall <hsw@openmoko.com>
+EdorFaus <edorfaus@gmail.com>
+Graham Gower <graham.gower@gmail.com>
+Krzysztof Kotlenga <pocek@users.sf.net>:
+Per Hansen <spamhans@yahoo.de>
+Mike Westerhof <mwester@dls.net>
+Antonio Ospite <ospite@studenti.unina.it>
+Koen Kooi <koen@beagleboard.org >
+Claudio Mignanti <claudyus84@gmail.com>
+Florian Boor <florian.boor@kernelconcepts.de>
+Camille Moncelier <moncelier@devlife.org>
+Jim Huang <jserv.tw@gmail.com>
+John L. Chmielewski <jlcster@gmail.com>
+
+
+== We don't have your name / email ==
+Gilles Doffe
+cconroy
+chgros
+Kosmaty
+manitu
+pblack88@gmail.com
+
+and anyone else who has sent patches or bug reports. If your name isn't on this
+list, please forgive us and send an email to a maintainer
+The project owners/committers is here: http://code.google.com/p/opkg/
diff --git a/src/.svn/text-base/COPYING.svn-base b/src/.svn/text-base/COPYING.svn-base
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/src/.svn/text-base/COPYING.svn-base
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/.svn/text-base/ChangeLog.ipkg.svn-base b/src/.svn/text-base/ChangeLog.ipkg.svn-base
new file mode 100644
index 0000000..5b86406
--- /dev/null
+++ b/src/.svn/text-base/ChangeLog.ipkg.svn-base
@@ -0,0 +1,1761 @@
+2006-05-30 pigi ( pigi@frumar.it)
+ * Version update to 0.99.163
+ * Fixed a bug in GNU_TAR_EXTENSION of unarchive.c. This fix #1666
+
+2006-05-04 pigi ( pigi@frumar.it)
+ * Fixed a little bug in makefile that inhibit the compilation from .tar.gz ( missing intercept dir )
+
+2006-04-20 pigi ( pigi@frumar.it)
+ * Version update to 0.99.162
+ * Fixed a bad bug introduced in .160 that was blocking the install of a package
+
+2006-04-18 pigi ( pigi@frumar.it)
+ * Version update to 0.99.161
+
+2006-04-18 pigi ( pigi@frumar.it)
+ * Another little fix for the upgrade part.Now alse the prerm and postrm scripts gets deleted before upgrading.
+ wishing this fix the last troubles in upgrade part.
+ * Fix for #1585 after the bug introduced with the modify for offline root. ( Again )
+
+2006-03-30 pigi ( pigi@frumar.it)
+ * Activated the patch from Gunter@ohrner.net for the md5 check of package
+ * Another change in the upgrade part, to handle the ghosts files from an upgraded package
+
+2006-03-30 pigi ( pigi@frumar.it)
+ * Version update to 0.99.160
+ * Fix for #1585 after the bug introduced with the modify for offline root.
+ * Patch from Gunter@ohrner.net that fix a memory leak
+ * Not yet activated, but inserted a patch from Gunter@ohrner.net for the md5 check of package
+
+2006-02-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.159
+ * Another change in the upgrade part, to handle the ghosts files from an upgraded package
+ * Now it should be ok. Thanks to pb_ for pointing out where to look at.
+
+2006-02-02 pigi ( pigi@frumar.it)
+ * Version update to 0.99.158
+ * Modified the way upgrade handle the removing of a package, to be sure that ipkg doesn't break busybox upgrade
+ * this should fix #1503
+
+2006-01-30 pigi ( pigi@frumar.it)
+ * applied patch from pb_ for speed up things in boot ( to avoid multiple configure execution )
+ * applied patch from <r.schwebel@pengutronix.de> for 100+ filenames in tar file ( again )!
+ * applied patch from <r.schwebel@pengutronix.de> to avoid trouble in offlineroot installations.
+
+2006-01-22 pigi ( pigi@frumar.it)
+ * Version update to 0.99.157
+
+2006-01-17 pigi ( pigi@frumar.it)
+ * Added a check to avoid reading feed files with several options. This should fix #1458 and speed up a lot of executions.
+
+2006-01-12 pigi ( pigi@frumar.it)
+ * Version update to 0.99.156
+ * Fixed a length problem for strncpy when "Installing" option added. This fix bug #1456. Thanks to hrw for signaling
+
+2005-12-15 pigi ( pigi@frumar.it)
+ * Version update to 0.99.155
+ * Added a function to remove the package that is being upgraded.
+ * Fixed a problem when installing by hand. Now ipkg knows that a package has been selected by hand,
+ * and, if every check returns ok, it install the wanted package, instead of selecting one from feed.
+ * Moreover, now downgrade should works again.
+ * Fixed the "Replaces" bug. Now ipkg is able to replace a package also if it doesn't conflict.
+ * Other minor changes in debug options
+
+2005-09-15 pigi ( pigi@frumar.it)
+ * Version update to 0.99.154
+ * Corrected a problem when removing a package, caused by an off by one alignement with the "Provides:" String
+ * Patched for the "depends:" bug introduced after the "Provides:" fix. This fix #1393
+ * Added a little fix for an off-by-one error in checking for depends.
+
+2005-07-29 pigi ( pigi@frumar.it)
+ * Applied a patch for the GNU tar compatibility . Now ipkg can handle filenames > 100 char.
+
+2005-07-29 pigi ( pigi@frumar.it)
+ * Version update to 0.99.153
+ * Fixed a problem with Provides:. Now ipkg is able to install foo when foo is provided by bar, and is able to determine the best candidate based on
+ * package name. This also fix #1328
+
+2005-07-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.152
+ * Fixed a length problem for strncpy after "Downgrading" option added. This fix bug #1373. Thanks to steven.scholz@imc-berlin.de for signaling
+
+2005-06-16 pigi ( pigi@frumar.it)
+ * Version update to 0.99.151
+ * Fixed a missing check for null pointers . This fix bug #1358
+
+2005-06-05 pigi ( pigi@frumar.it)
+ * Version update to 0.99.150
+ * Added the -force-downgrade option to allow the downgrade of a package
+
+2005-05-11 pigi ( pigi@frumar.it)
+ * Version update to 0.99.149
+ * Added the possibility to choice the ipkglibdir from configure ( --with-libipkgdir )
+
+2005-04-10 pigi ( pigi@frumar.it)
+ * Version update to 0.99.148
+
+2005-04-09 pigi ( pigi@frumar.it)
+ * Found a bug in output from error_list. Now every error is printed, also if the functions don't return an error.
+ * Added a patch to Makefile from Robert Schwebel <r.schwebel@pengutronix.de>, cleaning things a bit. Thanks to Schwebel
+
+2005-03-30 pigi ( pigi@frumar.it)
+ * Version update to 0.99.147
+ * Found a bug in ipkg_install when freeing a cursor
+
+2005-03-28 pigi ( pigi@frumar.it)
+ * Version update to 0.99.146
+ * Modified the ipkg_error messaging to collect all the messages at the end of the program
+
+2005-03-26 pigi ( pigi@frumar.it)
+ * Little bug in message when "depends broken"
+
+2005-03-14 pigi ( pigi@frumar.it)
+ * Version update to 0.99.145
+ * Found a bug in ipkg remove when a package was depending in itself and ipkg where asked to "-recursive"
+ This fix bug # 1301
+ * A very little beautify in args.c
+
+2005-03-07 pigi ( pigi@frumar.it)
+ * Added the check for md5 in resolv_conf_file. Now ipkg ask for confirmation only it the files differ
+
+2005-02-22 pigi ( pigi@frumar.it)
+ * Version update to 0.99.144
+ * A little fix suggested by drw in ipkg_conf.c
+ * Changed the ipkg.h to be build in automake for oe mechanism . This will enhance the building phase
+ by honouring the lib hierarchy choose by users
+ * Changes in automake to honour the new building mechanism
+
+2005-02-20 pigi ( pigi@frumar.it)
+ * Version update to 0.99.143
+ * libipkg.h: reverting the previous modify
+ * ipkg_conf.c: fixing a probable bug in list_dir that fix problems with opie-packagemanager ( tanks to drw for signaling)
+
+2005-02-20 pigi ( pigi@frumar.it)
+ * libipkg.h: added some define to fix the broken external interface after 0.99.139 and lists_dir
+
+2005-02-17 pigi ( pigi@frumar.it)
+ * pkg_depends.c: applied patch from rjt@cambridgebroadband.com to remove some c99ism
+
+2005-02-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.142
+ * Fixed the definition of full_write and full_read as per bug #1280
+
+2005-02-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.141
+ * Added space in ipkg_message to give more readible messages
+ * Corrected a problem when creating the directories in pkg_dest_init
+
+2005-02-05 pigi ( pigi@frumar.it)
+ * Version update to 0.99.140
+ * Fixed the bug in ipkg_conf for a wrong pointer.
+
+2005-02-05 pigi ( pigi@frumar.it)
+ * Version update to 0.99.139
+ * Fixed the "replaces" problem reported by pb_. Now ipkg is able to resolve a "replace/conflict" reference
+ * Added the possibility to keep the lists file in a different location. Fullfill enh #1276
+
+2005-02-02 pigi ( pigi@frumar.it)
+ * Fixed the problem for SW_DEINSTALL in remove. Fix #1274
+ * Fixed the problem issued from florian. This also fix the bug #520 HardLink are now supported
+
+2005-01-18 pigi ( pigi@frumar.it)
+ * Version update to 0.99.138
+ * libbb.h: patch for the uclib
+
+2005-01-14 pigi ( pigi@frumar.it)
+ * ipkg_install.c: applied patch from rjt@cambridgebroadband.com to remove some c99ism
+
+2005-01-14 jamey ( jamey@handhelds.org )
+ * pkg_hash.c: applied patch from Jean Tourrilhes to allow default
+ arch to be different than host arch
+
+2005-01-10 pigi ( pigi@frumar.it)
+ * Version update to 0.99.137
+ * fixed a little, but annoying bug when writing the status file.
+
+2005-01-10 pigi ( pigi@frumar.it)
+ * Version update to 0.99.136
+ * Lot of memory leak fixes from Benjamin Pineau <ben@zouh.org>
+ * Fix for the Provides, that weren't able to "protect" their dependants while removing.
+ Now the remove should be safer.
+ * removed the replace.h stuff from automake .ac/.in files. This should align to oe
+
+2005-01-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.135
+ * Various fix for dependencies in control files
+
+2005-01-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.134-1 for fixing a problem with cvs tag on previous version
+
+2005-01-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.134
+ * Added a new option for listing only the installed packages. Asked by pb_ but really important
+ * Little modification to autoconfigure.sh
+ * removed fileutils dependencies that has disappeared from 0.8 in control-cl.in control-unstripped.in libipkg-control.in
+
+2004-11-18 pigi ( pigi@frumar.it)
+ * Version update to 0.99.133
+ * Fix for preserve date and time when extracting a package. Thanks to <trevor.pering@intel.com>
+
+2004-10-07 pigi ( pigi@frumar.it)
+ * Version update to 0.99.132
+ * Little fix on available blocks calculation. Thanks to seved.torstendahl@netinsight.se for founding it.
+ * this fix #1259
+
+2004-09-20 pigi ( pigi@frumar.it)
+ * Version update to 0.99.131
+ * Added a lot of debug info in DEBUG2
+ * Added a check in ipkg_install.c to permit replacing of existing file when installing a package
+ * from a file ( not an upgrade ) when ipkg find a file clash but the owner of the package is the
+ * same. That should fix the #1246
+
+2004-09-02 pigi ( pigi@frumar.it)
+ * Version update to 0.99.130
+ * Added patch from pb_ for bug #1251. A lot of thanks to Phil
+
+2004-09-02 pigi ( pigi@frumar.it)
+ * Some changes on output messages to be a little bit clear
+
+2004-09-01 pigi ( pigi@frumar.it)
+ * Applied patches from pb_ (bug #1244)
+ * Added EXTRADIST = ipkg.c and others in Makefile.am as in ipkg.0.99.xxx.tar.gz the ipkg.c was missing. (
+ reported by odvard12@yahoo.com )
+ * Version update to 0.99.129
+
+2004-08-19 Florian <florian.boor@kernelconcepts.de>
+ * Version update to 0.99.128
+ * libipkg.c, ipkg_cmd.c: Fixed return value zero if installation
+ failed. Changed text because failing to install a package
+ is not necessarily a bug :-)
+ * Makefile.in, libbb/Makefile.in: Removed autogenerated files.
+
+2004-08-18 Florian <florian.boor@kernelconcepts.de>
+ * Two more fixed memory leaks. Contributed by Nils Faerber.
+
+2004-08-17 Florian <florian.boor@kernelconcepts.de>
+ * Fix to avoid major memory leak due to multiple initialising
+ of hash tables. Contributed by Nils Faerber.
+
+2004-07-20 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.127
+ * Applied patch from tmbinc@elitedvb.net (Felix Domke) to fix some problems when in use on platforms
+ * different from arm. Fixes big #1234
+2004-06-15 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.126
+2004-06-12 florian <florian.boor@kernelconcepts.de>
+ * Makefile.am: Added some missing headers to the list.
+ * libipkg.pc.in: Fixed hardcoded prefix... tsts
+2004-06-12 pigi ( pigi@frumar.it)
+ * pb_ patch for setuid bit in unarchive
+2004-06-05 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.125
+ * modified almost all reference to xregexec in fnmatch ( as adviced by zap).
+ This should fix every problem with strange character in package name when using regex in functions
+ ( as per info_status_cmd or remove ). #1220
+2004-05-21 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.124
+ * import the kergoth patch for Makefile.am to fix the linking problems on arch <> arm
+ * added the ipkg remove <regexp> feature.
+ * fixed the ipkg usage message, 'cause in "ifdef LIBIPKG" we don't have the ipkg info field version.
+ * added the message "No package removed" if no package has been removed. This to avoid misunderstanding
+ with the successfully done message at the exit of execution.
+2004-05-16 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.122-3
+ * Anothere little fix. Added the version number in control.in. This should fix definitelly the problem with dependencies
+2004-05-16 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.122-2
+ * New subrelease released to correct the problem for dependencies (libipkg >= 0.99.122-1) in ipkg control file
+2004-05-14 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.122-1
+ * needed for a recompilation with the libtool updated. This could fix the #1209 created by my old libtool version
+ * cleaned the cvs dir by removing the really unneeded busybox directory
+2004-05-10 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.122
+ * pb_, cworth and I discussed a bit on ipkg output to users. We agreed on removing some confusing
+ * messages, moving them to a debug level of verbosity.
+ * I do added also some message to user indicating the phase ipkg is in, and a global ending message
+ * informing the user for the status of operation.
+ * This fixes the #1206, and hopefully does not introduce others ;-)
+2004-05-03 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.121
+ * reenoo__ found a problem with depend lines > 1023, and pb fixed it. Thanks to both,
+ * This should fix #1204.
+2004-04-08 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.120
+ * pb found another one. The configure cmd now will set the correct values in status file
+ * #1196 fixed
+2004-04-07 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.119
+ * pb found another one. Commiting his patch, elegant as usual :)
+2004-03-29 jamey ( jamey@handhelds.org)
+ * configure.ac: updated to 0.99.118
+2004-03-29 pigi ( pigi@frumar.it)
+ * pb_ asked me to have a command to change the status of a package betwenn installed and unpacked.
+ and I did it.
+ * I' ve also included the fix for the empty lists as for bug # 1136 reported and suggested by k.vangelder@chello.nl
+2004-03-17 pigi ( pigi@frumar.it)
+ * Added the implement for Essential in status file. This is needed to avoid the unintentional remove
+ of essential packages. In effect the command "ipkg remove ipkg" worked without problems, but then
+ it was difficult to reinstall. This fix the bug # 867
+2004-03-15 jamey <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.117
+2004-03-10 pigi ( pigi@frumar.it)
+ * Added the check for *alloc in every source. I needed to modify some function ehre and there
+ to check the return values from function allocating memory, but hopefully it should be all right now.
+ * Added the check for at least a package for remove ( it was removing everithing if no pkgname followed the
+ remove option.
+2004-03-09 pigi ( pigi@frumar.it)
+ * Added a flag to disble the checking of directories when the command does not need to
+ read anything from there. Fix bug #1096
+2004-03-09 pigi ( pigi@frumar.it)
+ * Changes to correct the behaviour of verbosity. Now the "0" works, and the "1" is again
+ the default.
+ This fixes the bug #1099
+2004-03-07 pigi ( pigi@frumar.it)
+ * Minimal changes for a clean compile in libipkg.c ( so we can close the bug# 1119 )
+2004-03-03 pigi ( pigi@frumar.it)
+ * Missing \n in Size and Source Fields.
+2004-03-03 pigi ( pigi@frumar.it)
+ * Florian noticed a free missiing in ipkg_cmd.c ( should sleep more at night )
+ it was in an (almost) unsed part of the code ( old code ) but, just in case...
+ * Changed a comment in pkg.c ( it was in italian ) and added a bit of explain in
+ pkg_formatted_field
+2004-03-02 jamey <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.116
+ * pkg.h: from Pigi: pkg_formatted_info and pkg_formatted_field now allocate the strings they fill in
+ * pkg.c, ipkg_cmd.c: from Pigi: updated to the new pkg.h interface
+2004-02-29 florian <florian.boor@kernelconcepts.de>
+ pkg.c: Pigi and me poked around a little bit and located the cause of
+ latest segfault. strncat is not used correctly in pkg_formatted_info
+ and pkg_formatted_field. I added a fix to the only section that
+ triggered the bug and increased a buffer size.
+ BUT: There are many similar bugs remaining!
+2004-02-24 jamey <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.115
+ * ipkg_cmd.c: segv caught by pigi: buffer freed in loop but used on next iterations. bug squashed.
+ * user.c: realloc question buffer if it is too short so that messages are not truncated.
+2004-02-20 jamey <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.114
+ * libbb/unarchive.c: patch from pigi@frumar.it: fix erroneous invalid header checksum message
+2004-02-19 jamey <jamey.hicks@hp.com>
+ * configure.ac: update to 0.99.113
+ * libipkg.c: patch from drw to fix ipkg list
+2004-02-19 florian <florian.boor@kernelconcepts.de>
+ * Some minor changes to make code compile on more compilers.
+2004-02-14 jamey <jamey.hicks@hp.com>
+ * configure.ac: updated to 0.99.112
+ * libbb/unarchive.c: copied in oldgnu tar compatibility mode from latest busybox.
+2004-02-13 jamey <jamey.hicks@hp.com>
+ * configure.ac: updated to 0.99.111
+ * pkg.c: wim delvaux's patch for status file in other destinations
+2004-01-23 florian <florian.boor@kernelconcepts.de>
+ * Applied Dan's patch that adds a package download command to
+ libipkg.
+2004-01-20 florian <florian.boor@kernelconcepts.de>
+ * Applied Dan's changes to work incuded from a C++ app.
+2004-01-15 jamey
+ * configure.ac: updated to 0.99.110
+ * libipkg.c: added default callbacks for output
+ * ipkg_conf.c: default verbosity to 1
+2004-01-12 jamey
+ * configure.ac: updated to 0.99.109
+ * ipkg_install.c: fix potential segv sprintf_alloc with fewer args than required by format string (yay valgrind)
+ * sprintf_alloc.c: add null pointer checking
+2004-01-12 jamey
+ * configure.ac: updated to 0.99.108
+ * Makefile.am, familiar/: use ipkg-cl as default executable, install as ipkg via update-alternatives
+2004-01-12 jamey
+ * configure.ac: updated to 0.99.107
+ * void_list.c: check for null data
+ * pkg.c: check for null pointers
+2003-12-23 florian <florian.boor@kernelconcepts.de>
+ * Added void* parameter to some callbacks.
+
+2003-12-02 florian <florian.boor@kernelconcepts.de>
+ * Added familiar/ipkg-cl.control.in, which is a prototype of
+ control file for ipkg-cl package creation.
+2003-12-01 florian <florian.boor@kernelconcepts.de>
+ * added ipkg command line tool using libipkg, binary is known as ipkg-cl
+ * ipkg-frontend.c: source for this tool
+ * libbb/Makefile.am: Removed changing of CFLAGS, this avoids a nasty warning.
+ * Makefile.am: Same fix and addition of new target creating ipkg-cl.
+ * removed ltmain.sh, libtool which seem to be created by autostuff
+
+2003-12-01 jamey
+ * configure.ac: updated to 0.99.106
+ * pkg.c, ipkg_conf.c: check for null pointers (null pkg->dest in particular)
+2003-11-11 jamey
+ * configure.ac: updated to 0.99.105
+ * ipkg_conf.c: added verbosity option to conf file
+2003-11-11 jamey
+ * configure.ac: updated to 0.99.104
+ * ipkg_install.c: removed spurious calls to fflush, remove obsolete maintainer scripts on upgrade
+ * ipkg_remove.c: remove unused function: remove_conffiles
+2003-11-11 jamey
+ * configure.ac: updated to 0.99.103
+ * libipkg.pc.in, configure.ac: pkgconfig for libipkg
+ * ipkg_conf.c, pkg.c: check for error on fopen
+ * pkg_hash.c: reduced verbosity
+ * libtool: arm-linux-strip does not support --strip-debug on .a files
+2003-11-10 jamey
+ * configure.ac: updated to 0.99.102
+ * ipkg_cmd.c: compute architecture_priority of packages in database before doing download command
+ * conffile.c file_util.[ch] ipkg_install.c: better separation of installation root filenames and actual filenames
+ * pkg.h: added prototype for pkg_free_installed_files
+2003-11-10 jamey
+ * configure.ac: updated to 0.99.101
+ * libipkg changes
+ * generate .list files from file_hash
+2003-11-05 jamey
+ * configure.ac: updated to 0.99.100
+ * ipkg_install.c: fix segv: was passing conflictee->parent instead of conflictee
+2003-10-08 jamey
+ * configure.ac: updated to 0.99.99
+ * ipkg_install.c: use the root_dir after stripping off offline_root prefix
+2003-10-08 jamey
+ * configure.ac: updated to 0.99.98
+ * pkg_hash.c: fixed segv if replaced_by->len was 0
+ * ipkg_cmd.c: ipkg remove with no arguments will remove non-user leaf packages
+ * ipkg_remove.[ch]: export pkg_has_installed_dependents
+ * pkg_depends.c: add pkg->parent to pkg->provides
+ * ipkg_install.c: strip offline_root prefix off of conffile name so comparing the md5sums should work
+ * pkg.c: missing comma added
+2003-10-01 jamey
+ * configure.ac: updated to 0.99.97
+ * ipkg_cmd.c: added whatdependsrec command to show what recursively depends on a package or packages
+ * pkg_vec.[ch]: added pkg_vec_clear_marks and pkg_vec_mark_if_matches
+ * args.c: usage string updated
+2003-09-28 jamey
+ * configure.ac: updated to 0.99.96
+ * ipkg_conf.c: adjusted verbosity
+ * ipkg_install.c: only remove replacee if it is also conflicted, per debian standard
+ * pkg_depends.c: only add to replaced_by if it also conflicts, per debian standard
+ added pkg_provides, pkg_replaces, pkg_conflicts
+ * pkg_hash.c: adjusted verbosity
+2003-09-28 jamey
+ * configure.ac: updated to 0.99.95
+ * args.[ch], ipkg_cmd.c, ipkg_conf.[ch], ipkg_download.c, ipkg_install.c, ipkg_remove.c, pkg.[ch]:
+ Implemented -test mode for ipkg.
+2003-09-28 jamey
+ * configure.ac: updated to 0.99.94
+ * pkg_hash.c: fix pkg_hash_fetch_best_installation_candidate so
+ that one can install another provider of an installed package name
+2003-09-26 jamey
+ * configure.ac: updated to 0.99.93
+ * ipkg_install.c: corrected message level depending on conf->force_depend
+ * ipkg_conf.c: check for duplicate src entries
+ * nv_pair_list.[ch]: added nv_pair_list_find
+2003-09-16 jamey
+ * configure.ac: updated to 0.99.92
+ * pkg_depends.c: some paranoia to try to avoid segv
+ * void_list.c: silenced message about elt not being found
+2003-09-11 jamey
+ * configure.ac: updated to 0.99.91
+ * pkg_depends.c: added pkg_depend_str to fetch right kind of dependence string based on dependence index
+ Use this in add_unresolved_dep.
+ * pkg_depends.h: declaration of pkg_depend_str
+2003-08-22 11:02 jamey
+ * configure.ac: updated to 0.99.90
+ * str_list.[ch]: added str_list_alloc(), added str_list_remove_elt()
+ * void_list.[ch]: added void_list_remove_elt()
+ * pkg_parse.c: added parsing of Source field
+ * pkg_hash.c: updated old_pkg->installed_files list when setting file owner if it was previously owned by old_pkg
+ * pkg_extract.c: use installed_file list if it exists in pkg_extract_data_file_names_to_file
+ * pkg.[ch]: added pkg_write_filelist() and pkg_write_changed_filelists()
+ * ipkg_remove.c: do not call ipkg_conf_write_status_files from ipkg_remove
+ * ipkg_install.c: use ipkg_write_filelist()
+ * ipgk_cmd.c: after writing status file, write any changed pkg filelists
+2003-08-20 11:02 jamey
+ * configure.ac: updated to 0.99.89
+ * pkg.c: print Source field in pkg_print_info
+2003-08-06 18:34 jamey
+ * configure.ac: updated to 0.99.88
+ * pkg_hash: bug 942, declare internal induction variable
+ * ipkg_cmd.c, ipkg_conf.[ch], pkg_src.[ch], pkg_src_list.[ch]: bug 604, support Packages.gz
+2003-08-06 18:34 jamey
+ * configure.ac: updated to 0.99.87
+ * pkg.c: remove extra printing of Suggests field
+ * pkg_vec.c: merge Status field only from current database, rest of Package info from Packages files
+ * pkg_depends.c: print info about recommendations as Notice instead of DEBUG
+2003-07-11 18:34 jamey
+ * configure.ac: updated to 0.99.86
+ * ipkg.h, ipkg_cmd.c, ipkg_configure.c, ipkg_install.c, ipkg_remove.c: only write status file if something changed.
+2003-07-11 18:34 jamey
+ * configure.ac: updated to 0.99.85
+ * pkg.c, pkg.h, pkg_depends.c, pkg_depends.h, pkg_parse.c: bug 885:
+ add recommends and suggests
+ * args.c, ipkg_cmd.c, ipkg_cmd.h: add ipkg configure command
+ * pkg_vec.c: apply patch for bug 883
+2003-05-11 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.84
+ * pkg.c, ipkg-compare-versions.c: fix problem where . and - were not treated as separators in version comparison
+2003-04-11 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.83
+ * ipkg_install.c: use pkg->installed_size instead of pkg->size
+ * ipkg_cmd.c, ipkg_conf.c: put lists under offline_root if specified
+2003-04-11 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.82
+ * pkg_hash.c: ignore Replaces directive when a package replaces itself
+2003-04-10 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.81
+ * pkg.c: clear state_want and state_flags for any uninstallable package
+2003-04-10 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.80
+ * pkg.c: pkg_merge was intermingling depends and predepends from
+ old and new pkg, and was ignoring conflicts and replaces
+ * pkg_depends.c: cleaned up interface to parseDepends
+2003-04-07 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.79
+ * pkg_hash.c: default architecture to host_cpu if unspecified
+ * ipkg_install.c, ipkg_download.c: refuse to install package with no architecture
+2003-04-07 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.78
+ * args.[ch], ipkg_conf.[ch]: added query_all (-A)
+ * ipkg_cmd.c: finished implementing whatdepends, whatrequires, whatprovides, and whatconflicts
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.77
+ * ipkg_cmd.c: implemented whatdepends
+ * ipkg_conf.c: fixed typo
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.76
+ * args.c: was zeroing args structure too late
+ * ipkg_conf.c: test for existence of /etc/ipkg.conf before trying to load it
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.75
+ * familiar/rules: update postinst only to generate ipaqarch.conf if none exists
+ * args.[ch]: added -t or --tmp-dir option to specify tmp-dir
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.74
+ * ipkg_cmd.c: avoid segv by only calling xregfree after xregcomp was called
+ * pkg_hash.c: prefer pkgs that are marked hold/prefer, next
+ abstract pkgs that are installed, next latest pkg if one provider,
+ give up if multiple providers are acceptable -- let user decide
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.73
+ * pkg_hash.c: remove latest_installed heuristic because it prevents upgrades.
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.72
+ * pkg_hash.c: check for unresolved packages (apkg->provided_by->len == 0), better messages.
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.71
+ * pkg.c: Added pkg_name_version_and_architecture_compare and abstract_pkg_name_compare
+ * ipkg_cmd.c: allow multiple fields for info and status command.
+ Allow posix regexp's for package name in status, info, and list
+ commands.
+ * pkg_remove.c: fixed type error
+ * xregex.h: added xregfree
+ * pkg_hash.c: Provides functionality seems to be working again
+2003-04-02 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.70
+ * args.c, args.h, ipkg_conf.c, ipkg_conf.h, ipkg_install.c: implemented nodeps option
+ * pkg_vec.[ch]: added [abstract_]pkg_vec_{contains,sort}
+ * pkg.c: print which script not being run in offline root mode
+2003-04-02 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.69
+ * pkg_vec.c: compare architecture to architecture, not to name
+ * ipkg_utils.c: do not exit, instead return NULL
+ * ipkg_install.c: do not exit, instead return -EINVAL
+ * ipkg_download.c: make sure to set pkg dest
+ * ipkg_cmd.c: notice instead of info for writing status file message
+2003-04-02 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.68
+ * pkg_vec.c, pkg_depends.c: pkg_t's are the same if they have same name, version, and architecture
+2003-04-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.67
+ * ipkg_install.c: one last check for supported architecture in ipkg_install_pkg
+ * pkg.c: make pkg_print_field less fragile by using strcasecmp,
+ added support to print Conflicts
+ * pkg_hash.c: if multiple candidates with right architecture
+ satisfy constraint_fcn, return latest version
+ * ipkg_cmd.c: when verbosity > 1, show if conffiles have been
+ modified in info command
+ * hash_table.c, hash_table.h: count number of elements in hash
+ tables
+ * file_util.c: explicitly use unsigned char
+ * conffile.c: more debugging info
+2003-04-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.66
+ * pkg_depends.c: fixed what seemed to be glaring deficiency in version_constraints_satisfied
+ * pkg_hash.c: more debug info
+ * pkg_parse.c, pkg.c: added Installed-Time as field saved to status file
+2003-04-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.65
+ * ipkg_cmd.c, ipkg_conf.c: applied ipkg dest installation patch from Ben Lau <benlau@linux.org.hk>
+ * ipkg_cmd.c: fixed probably segv when using offline_root, fixed problem installing from local file.
+ * ipkg_conf.c:
+ - Do not add default architectures if ipkg configuration files include architecture definitions.
+ - Look for /etc/ipkg/*.conf under offline root if using offline root mode
+ * void_list.h: added void_list_empty()
+ * nv_pair_list.h: added nv_pair_list_empty()
+2003-03-28 14:30 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: 0.99.64
+ * pkg_hash.c: change fprintf stderr to ipkg_message
+ * pkg.h: added SF_MARKED and abstract_pkg_t state_flag field
+ * pkg.c: include Provides, Replaces, and Architecture in status
+ file
+ * ipkg_remove.c: make sure to print each dependent package only
+ once
+ * ipkg_message.h: added IPKG_DEBUG2
+ * ipkg_install.c: modify message and level depending on
+ force_depends
+ * ipkg_cmd.c: call pkg_info_preinstall_check before any
+ install/upgrade/remove action
+ * ChangeLog, autoconfigure.sh, includes.h,
+ ipkg_conf.c, ipkg_remove.c, pkg.c, pkg.h, update-alternatives,
+ xregex.h: applied kergoth's update-alternatives patch
+ * ipkg_cmd.c, ipkg_remove.c: remove maybe_broken_removal... which
+ was an expensive no-op; before removing package, make sure that
+ nothing is installed that depends on the apkgs **provided** by a
+ package
+ * pkg.h: mark for future cleanup
+ * ChangeLog: 0.99.62, adds architecture priority, better handling
+ of file obsolescence and package replacements in progress
+2003-03-27 18:26 jamey
+ * autoconfigure.sh: accidentally committed /usr/local/bin calls
+ * ipkg_conf.c: needed a strdup, set default verbosity back to 0
+ * familiar/postinst: default architecture priorities
+ * Makefile.in, autoconfigure.sh, ipkg_cmd.c, ipkg_conf.c, pkg.c:
+ both name and value in nv_pair_list must be actual strings
+ * pkg_hash.c: do not try to invoke NULL constraint_fcn
+ * ipkg_install.c: added file_hash_{set,get}_file_owner, created
+ check_downgrade
+ * ipkg_conf.c, ipkg_conf.h, ipkg_remove.c, pkg.c, pkg_hash.c,
+ pkg_hash.h: added file_hash_{set,get}_file_owner
+ * hash_table.c: check for key already being present in
+ hash_table_insert
+ * configure.ac: update to 0.99.63
+ * ipkg_hash_test.c: update due to new prototypes
+ * ipkg_conf.c: missed a conversion from str_list to nv_pair_list
+ * ipkg_install.c: minor tweaks
+ * pkg.c, pkg.h: added pkg_info_preinstall_check to update
+ pkg->arch_priority
+ * pkg_depends.c, pkg_depends.h: use constrained
+ pkg_hash_fetch_best_installation_candidate in
+ pkg_hash_fetch_unsatisfied_dependencies
+ * pkg_hash.c, pkg_hash.h, ipkg_cmd.c, ipkg_upgrade.c: split
+ pkg_hash_fetch_best_installation_candidate into a by name and a
+ constrained version
+ * ipkg_install.c: block SIGINT while doing core of package
+ installation (single package)
+ * ipkg_conf.c, ipkg_conf.h: support for architecture priority
+ * pkg_depends.c: cleanup, reindent
+ * pkg.c, pkg.h: support for architecture_priority
+ * ipkg_cmd.c: installed SIGINT handler when upgrading or removing,
+ support for architecture_priority
+ * pkg_hash.c: added support for architecture priority, reindented
+ * pkg_vec.c: minor cleanup
+2003-03-24 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.61
+ * familiar/postinst: mkdir -p /etc/ipkg
+2003-03-24 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.61
+ * ipkg_conf.c: read configuration from all *.conf files in /etc/ipkg/
+ * familiar/postinst: create /etc/ipkg/*.conf according to platform ipkg is installed on
+2003-03-20 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.60
+ * various: added support for package architectures
+ * configure.ac: do not test for malloc
+2003-03-17 Aman Gupta <ipkg@themastermind1.net>
+ * configure.ac: updated to 0.99.59
+ * args.c: show all verbosity levels in usage info
+ * args.h: changed default verbosity level to 1
+ * ipkg_cmd.c: ipkg_multiple_files_scan() was useless, switch to using
+ ipkg_prepare_url_for_install()
+ * ipkg_install.c: fix --force-reinstall
+ * ipkg_remove.c: stop removing of modified conffiles
+2003-03-04 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.56
+ * ipkg_message.c: show error messages by default
+ * ipkg_message.h: protect against multiple inclusion
+ * conffile.[ch]: switch to ipkg_message, added conf argument to conffile_has_been_modified
+ * ipkg.h: move EXTENSION macros here
+ * pkg_depends.c: minor cleanup
+ * pkg.h: added prefer and obsolete flags
+ * pkg.c: parse and unparse SF_PREFER and SF_OBSOLETE
+ * ipkg_install.[ch]:
+ - added {pkg,name}_mark_dependencies_for_installation,
+ - added conf argument to conffile_has_been_modified
+ - missing ifdef IPKG_DEBUG_NO_TMP_CLEANUP
+ * ipkg_remove.c: added conf argument to conffile_has_been_modified
+ * ipkg_download.c: added ipkg_prepare_for_install
+2003-03-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.55
+ * ipkg.h: wrap #if 0 around definition of of IPKG_DEBUG_NO_TMP_CLEANUP
+2003-03-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.54
+ * ipkg_install.c: make old package SW_DEINSTALL during ipkg installation
+ * ipkg_cmd.[ch]: added some code to install packages marked SW_INSTALL, but have not enabled this code yet.
+2003-03-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.53
+ * pkg_depends.c: let SW_INSTALL satisfy dependences (instead of SS_INSTALL)
+2003-03-01 Daniele Nicolodi <daniele@grinta.net>
+ * ipkg_install.c: indentation fixes and finish switch to message
+ facility
+ * ipkg_cmd.c: indentation fixes, switch to message facility and
+ some code cleanup
+ * ipkg_message.c (ipkg_message): check for a NULL *conf parameter
+ * ipkg_message.h: renamed IPKG_ERR in IPKG_ERROR
+2003-02-28 Jamey Hicks <jamey@handhelds.org> (patch from Daniele Nicolodi <daniele@grinta.net>)
+ * configure.ac: incremented version to 0.99.5
+ * ipkg_message.[ch]: added message facility
+ * args.[ch]: verbosity control
+ * ipkg_conf.[ch]: verbosity control
+ * ipkg_install.c: switch to using message factility
+2003-02-28 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version to 0.99.51
+ * ipkg_cmd.c: added ipkg_statisfy_all_dependences, called after
+ install/upgrade of packages to handle packages that were split and
+ no longer provide all the resources they used to provide.
+2003-02-27 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version to 0.99.50
+ * ipkg_cmd.c: write out status after doing an upgrade
+2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb)
+ * configure.ac: incremented version to 0.99.49
+ * pkg_parse.c, pkg.c: do not treat deb revision specially
+2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb)
+ * configure.ac: incremented version number to 0.99.48
+ * args.c: added help for ipkg flags sub-command
+ * ipkg_cmd.c: added ipkg_flag_cmd, do not upgrade package marked hold
+ * ipkg_install.c: do not remove obsolesced files if old_pkg is flagged noprune
+ * ipkg_remove.c: pkg->state_flag is a bitvector now
+ * pkg.c: pkg->state_flag is a bitvector now
+ * pkg.h: pkg->state_flag is a bitvector now
+2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb)
+ * configure.ac: incremented version number to 0.99.47
+ * pkg.c: refix "uninstalled package has NULL tmp_unpack_dir"
+ * pkg_hash.c:
+2003-02-27 Aman Gupta <oz@themastermind1.net> (another patch from pb_)
+ * configure.ac: incremented version number to 0.99.46
+ * pkg.c: fix "uninstalled package has NULL tmp_unpack_dir"
+2003-02-24 Jamey Hicks <jamey@handhelds.org> (per patch from Philip Blundell <pb@handhelds.org>)
+ * configure.ac: incremented version to 0.99.45
+ * file_util.c: include space for null in line_size
+ * ipkg_cmd.c: sigint handler while configuring packages
+ * ipkg_install.c: state_status != SS_INSTALLED and != SS_UNPACKED
+ * ipkg_remove.c: missing i++
+ * pkg.c: do not run scripts in offline_root mode
+ * pkg_depends.c: every package provides itself
+ * pkg_hash.c: better handling of packges provided by multiple providers
+2003-02-24 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version number to 0.99.44
+ * args.c: added doc for -force-overwrite
+2002-11-26 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version number to 0.99.43
+ * ipkg_install.c: completely skip the space check when -force_space asserted
+2002-11-23 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version number to 0.99.42
+ * args.c: missed one spot checking for -force_space or -force-space
+2002-11-23 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version number to 0.99.41
+ * ipkg_install.c: added -force_space option to override out of space check
+2002-11-23 Aman Gupta <oz@themastermind1.net>
+ * configure.ac: incremented version number to 0.99.40
+ * ipkg_configure.c: updated to match new text output format
+ * ipkg_install.c: updated to new text output format
+ fixed problems where ipks installed from file or
+ http were being installed over newer ipks of the
+ same name
+ * ipkg_remove.c: updated to new text output format
+ made ipkg remove do what ipkg purge originally did,
+ by having it remove conffiles, and status entries for
+ ipks that are removed. ipkg_purge now calls
+ ipkg_remove
+2002-11-22 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.39
+ * applied patches from Aman Gupta for better handling of dests
+2002-11-?? Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.38
+2002-11-07 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.37
+ * hash_table.[ch]: moved internals of hash_tables out of pkg_hash.c
+ * pkg_hash.c: moved internals of hash_tables out of pkg_hash.c
+2002-10-29 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.37
+ * ipkg_cmd.c: ipkg_upgrade_cmd now installs uninstalled packages
+ instead of getting a segv
+2002-10-29 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.36
+ * changed verbose_get to verbose_wget as documented
+2002-08-08 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.34
+ * ipkg_cmd.c: fixed problem stringifying HOST_CPU
+ * Makefile.am: helped fix problem stringifying HOST_CPU
+2002-08-08 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.33
+ * ipkg_cmd.c, args.c: added print-architecture and print-installation-architecture commands
+ * Makefile.am: added defines for HOST_CPU and BUILD_CPU to CFLAGS and package: target
+2002-08-08 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.32
+ * pkg.c: removed chroot breakage
+2002-08-07 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.31
+ * other: applied multiple providers patch from philip blundell
+ * ipkg_cmd.c: implemented compare_versions cmd
+2002-07-25 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.30
+ * ipkg_conf.c: added offline_root_pre_script_cmd and offline_root_post_script_cmd
+ * pkg.c: execute scripts in chroot'ed environment running
+ pre_script_cmd and post_script_cmd before and after the pkg script.
+2002-07-24 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.29
+ * pkg.c: fixed a segv when printing Replaces field
+2002-07-24 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.28
+ * ipkg_cmd.c: merged functionality from ipkg_install_cmd into
+ ipkg_upgrade_cmd with an eye towards unifying these two commands.
+ * ipkg_install.c: installing a package that replaces other
+ packages removes them first. (Upgrade does not do replacements automatically).
+ * ipkg_remove.c: ipkg_remove_pkg will remove a package with
+ installed dependents if state_flag == SF_REPLACE.
+2002-07-24 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.27
+2002-07-23 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.26
+ * renamed pkg_vec_init/pkg_vec_deinit to pkg_vec_alloc/pkg_vec_free
+ * started implementation of Replaces
+2002-07-22 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.25
+ * many cleanups trying to regain stability
+2002-07-22 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.24
+ * various files: trying to stomp a segv in conflicts checking.
+2002-07-17 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.23
+ * ipkg_remove.c: do not do recursive removal if force-depends is
+ specified
+ * other-files: other cleanups to reduce code clutter
+2002-07-16 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.22
+ * user.[ch]: moved user interaction procedure here
+ * args.[ch], ipkg_conf.[ch]: added force_removal_of_dependent_packages
+ * pkg.h: added state_status to abstract_pkg_t
+ * ipkg_remove.c: If package has installed dependents, then only
+ remove if force_removal_of_dependent_packages is asserted in
+ ipkg.conf or on command line. Will add user interaction option later.
+2002-07-16 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.21 after
+ applying dependent removal and conflicts patch.
+
+2002-07-14 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.20
+ * ipkg_download.c: removed useless -N flag from wget
+ * update-alternatives: 'head -1' -> 'head -n 1', no sort -k 2 for busybox
+
+2002-07-15 Karthikeyan K <karthik@innvo.com>
+
+ * ipkg_remove.c (ipkg_remove_dependant_pkgs): removed setting the
+ dependencies_checked variable in the while loop b4 actually checking
+ the dependencies of that package.
+ * ipkg_cmd.c (ipkg_multiple_files_scan): added check for ".ipk" and
+ ".deb" extension, so that no caching is attempted on arguments that
+ are not local files
+ * pkg_depends.c (pkg_hash_fetch_conflicts): while returning NULL,
+ casted to (pkg_vec_t *) to compile without warnings
+
+2002-07-12 Abhaya Shenoy <abhaya@innvo.com>
+
+ * pkg_depends.c (pkg_hash_fetch_conflicts): use new abstract_pkg_vec
+ structure in checking provided_by
+
+2002-07-07 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.18
+ * fixed a segv due to type error in provides support
+
+2002-07-07 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.17
+ * updated provides support so that installed provider is preferred to
+ uninstalled provider
+
+2002-07-05 Abhaya Shenoy <abhaya@innvo.com>
+
+ * pkg_depends.c (pkg_hash_fetch_conflicts): check for conflicts
+ found before returning
+
+2002-07-04 Abhaya Shenoy <abhaya@innvo.com>
+ * ipkg_install.c (check_conflicts_for): new function to call
+ pkg_hash_fetch_conflicts and print offending packages
+ (ipkg_install_pkg): added call to check_conflicts_for
+ * pkg.c (pkg_merge): provides from oldpkg should be given
+ priority
+ (pkg_init): init of conflicts, conflicts_count fields
+ * pkg.h (struct pkg): added fields conflicts_str, conflicts,
+ conflicts_count
+ * pkg_depends.c (pkg_hash_fetch_conflicts): new function to check
+ for conflicts
+ (buildConflicts): new function to set up the conflicts in the pkg
+ struct
+ * pkg_depends.h: added new type CONFLICTS to depend_type enum
+ * pkg_hash.c (hash_insert_pkg): added call to buildConflicts
+ * pkg_parse.c (pkg_parse_raw): added parsing of Conflicts
+
+2002-07-04 Karthikeyan K <karthik@innvo.com>
+
+ * ipkg_cmd.c (ipkg_multiple_files_scan): new function to handle installation
+ of already downloaded files
+ (ipkg_install_cmd): added call to ipkg_multiple_files_scan
+ (ipkg_remove_cmd): added call to possible_broken_removal_of_packages
+ * ipkg_install.c (ipkg_install_pkg): added check to remove redundant upgrade
+ when a package to be installed is already installed as a dependancy of
+ another
+ * ipkg_remove.c (possible_broken_removal_of_packages): new fnuction
+ to check that all packages can be removed, before actually starting to
+ remove them
+ (ipkg_remove_dependant_pkgs): new function to remove dependant packages
+ (ipkg_remove_pkg): added call to ipkg_remove_dependant_pkgs
+ * pkg.c (abstract_pkg_init): initialized dependencies_checked
+ * pkg_hash.c (pkg_hash_dump): added more information to hash dump
+
+2002-07-03 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.16
+ * ipkg_install.c: defensive programming in case pkg contains no Size: clause
+
+2002-07-02 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.15
+ * pkg_depends.c: check for provided_by when fetching unsatisfied dependencies
+
+2002-07-02 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.14
+ * pkg_hash.c: if abstract pkg is provided_by, then return pkg vec
+ of first package that provides it.
+
+2002-06-17 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.12
+ * args.h, ipkg_conf.h, ipkg_install.c: Added force_overwrite
+ option. When this is asserted, ipkg will overwrite files that
+ have no owner or that belong to other packages.
+ * ipkg_conf.c, ipkg_dest.c: Update status file atomically, keeping
+ old copy of status file if cannot update new status file. Applied
+ patch from Jukka Santala for this fix.
+
+2002-03-16 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version number to 0.99.9-1.
+
+ * RELEASE_NOTES: Added release notes for 0.99.9-1.
+
+2002-03-15 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version number to 0.99.9.
+
+ * RELEASE_NOTES: Added release notes for 0.99.9.
+
+ * Makefile.am (bin_PROGRAMS): Install update-alternatives as well.
+
+ * familiar/rules (binary-arch): Mv all of /bin to /usr/bin
+
+ * configure.ac: Incremented version number to 0.99.8.
+
+ * RELEASE_NOTES: Added release notes for 0.99.8.
+
+ * familiar/rules (binary-arch): Fixed to use "make install-strip"
+ rather than "make install" and a strip command.
+
+ * ipkg_cmd.c (ipkg_install_cmd): Moved an error message up from
+ ipkg_install_by_name, (eventually all error messages should come
+ up out of what will become libipkg, (pkg.c, ipkg_install.c, etc.)
+ and into ipkg_cmd.c and friends).
+ (ipkg_upgrade_pkg): Pushed downgrade check down into
+ ipkg_install_by_name so that "ipkg install foo" will do the
+ downgrade check.
+
+ * ipkg.h: Rename some ipkg_error_t error codes to be more
+ consistent.
+
+ * ipkg_install.c (resolve_conffiles): Added missing removal of
+ backed-up modified conffiles, (which led to bizarre, bogus
+ conffile prompting the next time the package was upgraded).
+ (user_prefers_old_conffile): Fixed reversed arguments to diff in
+ interactive conffiles prompting.
+ (ipkg_install_by_name): Fixed "ipkg install foo" to never
+ downgrade foo, (just like "ipkg upgrade foo").
+
+ * familiar/rules: Added installation of
+ /usr/share/doc/ipkg/copyright file. Fixed so that ipkg.conf goes
+ to /etc, not /usr/etc, (but still keep binary in /usr/bin not
+ /bin). Changed name of installed binary from ipkg-unstable to
+ ipkg.
+
+ * familiar/control.in (Package): Changed package name from
+ ipkg-unstable to ipkg.
+
+ * pkg_parse.c (parseVersion): Fixed to ignore whitespace at
+ beginning of version string.
+ (pkg_parse_raw): Fixed segfault if a package record list ends with
+ a package paragraph without a final blank line.
+
+ * ipkg_install.c (check_data_file_clashes): Improved wording of
+ file clash error message.
+
+ * ipkg_download.c (ipkg_download_pkg): Fixed segfault if package
+ has no src, (occurs if package had benn installed locally, then
+ was removed (but not purged), then tried to reinstall eithout it
+ existing in any /usr/lib/ipkg/lists/* file).
+
+ * etc/ipkg.conf: Added a default ipkg.conf to the distribution.
+
+2002-03-13 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version to 0.99.7.
+
+ * RELEASE_NOTES: Added release notes for 0.99.7.
+
+ * pkg.c (pkg_run_script): Added support to export
+ IPKG_OFFLINE_ROOT. This is really a nasty hack as it means scripts
+ need to be modified to check IPKG_OFFLINE_ROOT. I'd really prefer
+ coming up with a good, reliable chroot system. But for now this
+ will let update-alternatives work, (which already does examine
+ IPKG_OFFLINE_ROOT).
+ (pkg_run_script): Added missing brace.
+
+ * ipkg_conf.c (ipkg_conf_init): Reworked significantly to properly
+ set up the pkg_dest_list stuff to account for offline_root.
+
+ * args.c (args_parse): Added support for -force_defaults in
+ addition to -force-defaults, etc. as I kept mistyping these
+ somehow.
+
+2002-03-12 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version to 0.99.6.
+
+ * RELEASE_NOTES: Added release notes for 0.99.6.
+
+ * ipkg_download.c (ipkg_download): Fixed bug in handling of
+ "file://" URLs.
+
+ * ipkg.c (main): Fixed to abort if ipkg_conf_init fails.
+
+ * ipkg_conf.c (ipkg_conf_init): Fixed to complain if given an
+ unknown dest.
+
+ * pkg.c (pkg_print_field): Fixed several fields to not print if
+ NULL, (Architecture. Maintainer, Size, Filename, Description)
+
+ * args.c (args_parse): Fixed bug that was always setting
+ force_removal_of_essentail_packages (yikes!).
+
+ * configure.ac: Incremented version to 0.99.5.
+
+ * RELEASE_NOTES: Added release notes for 0.99.5.
+
+ * familiar/rules (binary-arch): Added strip back in in preparation
+ of non-unstable release of ipkg.
+
+ * str_util.c (str_starts_with): Added convenience function.
+
+ * pkg_extract.c (pkg_extract_data_file_names_to_file): Fixed
+ filenames in *.list files to be compatible with dpkg and the old
+ ipkg, (no prefix of "." for example).
+
+ * pkg.c (pkg_run_script): Added export of PKG_ROOT for the benefit
+ of maintainer scripts.
+
+ * ipkg_remove.c (ipkg_remove_pkg): Complain and abort if user
+ attempts to remove an essential package, (also inform them of the
+ force option if they insist).
+
+ * ipkg_install.c (ipkg_install_pkg): Added message about whether
+ installing or upgrading.
+
+ * ipkg_download.c (ipkg_download): Added support for "file://"
+ URLs, (untested).
+ (ipkg_download): Added support for wget proxy options.
+
+ * ipkg_conf.c (ipkg_conf_init): Added proxy support to ipkg_conf,
+ (http_proxy, ftp_proxy, no_proxy, proxy_user, and proxy_passwd).
+
+ * ipkg_cmd.c (ipkg_upgrade_pkg): Moved Upgrading message from
+ ipkg_upgrade_cmd to ipkg_install_pkg.
+
+ * args.c (args_parse): Added new option
+ -force-removal-of-essential-packages, (which is intentionally
+ painful to type and not listed in usage. It should not be used
+ often).
+
+2002-03-11 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version to 0.99.3.
+
+ * RELEASE_NOTES: Added release notes for 0.99.3.
+
+ * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Fixed
+ to avoid infinite loop in the case of a circular dependency.
+
+ * configure.ac: Incremented version to 0.99.2.
+
+ * RELEASE_NOTES: Added release notes for 0.99.2.
+
+ * familiar/rules: Commented out strip, (temporary until this beast
+ is deemed more stable).
+
+ * xsystem.c (xsystem): Cleaned up error message, (missing
+ newline).
+
+ * pkg.c (pkg_merge): Made pkg_merge a NOP if oldpkg == newpkg.
+ (pkg_print_field): Don't print MD5sum field if NULL.
+
+ * ipkg_install.c (satisfy_dependencies_for): Now returns error
+ status if one or more of the dependencies fail to install cleanly.
+ (unpack_pkg_control_files): Fixed to not tack on a bunch of
+ NULL-valued conffiles entries if non-NULL conffiles already
+ exist. This fixed the errant prompting for unmodified conffiles
+ during -force-reinstall.
+ (unpack_pkg_control_files): Cleaned up conffile filenames to not
+ have ugly things like "///" inside them.
+
+ * ipkg_download.c (ipkg_download): Cleaned up error message.
+ (ipkg_download): Now uses new file_move function.
+ (ipkg_download_pkg): Created new function, (from old code in ipkg_install).
+
+ * ipkg_cmd.c (ipkg_download_cmd): Added new "ipkg download"
+ command.
+
+ * file_util.c (file_move): Created file_move, (from code that had
+ been in ipkg_download).
+ (file_copy): Added error message on failure.
+
+ * conffile.c (conffile_has_been_modified): Eliminated crash if
+ conffile_has_been_modified is called with conffile->value == NULL.
+
+2002-03-09 Carl Worth <cworth@east.isi.edu>
+
+ * RELEASE_NOTES: Added release notes for 0.99.1
+
+ * configure.ac: Incremented version to 0.99.1
+
+ * pkg_hash.c (pkg_hash_pkg_owning_file): Fixed to actually return
+ NULL if no package owns a file.
+
+ * pkg.c (pkg_get_installed_files): Added installed_files_ref_cnt
+ to pkg_t to prevent pkg->installed_files from being freed from an
+ inner loop while still being used by an outer loop, (which was
+ happening).
+
+ * pkg_hash.c (pkg_hash_pkg_owning_file): Moved this function in
+ from pkg_dest.c. Also, updated it to use pkg_get_installed rather
+ than mucking around inside /usr/lib/ipkg and globbing for *.list
+ files.
+ (pkg_hash_fetch_best_installation_candidate): Fixed to only return
+ a package that actually could be installed, (ie. it must have
+ either a local_filename or a non-NULL src from which it could be
+ downloaded). This prevents a segfault during "ipkg upgrade".
+
+ * pkg.c (pkg_get_installed_files): Fixed to not do strange things
+ to filenames such as: "//./bin/sh"
+
+ * ipkg_cmd.c (ipkg_files_cmd): Added pkg_free_installed_files to
+ conserve a bit of memory.
+ (ipkg_search_cmd): Updated to use pkg_get_installed rather than
+ mucking around inside /usr/lib/ipkg and globbing for *.list files.
+
+ * pkg.c (pkg_free_installed_files): Added this function to free up
+ memory from pkg_get_installed_files.
+
+ * ipkg_conf.c (ipkg_conf_set_option): Added force_reinstall option
+ to allow reinstallation of an installed package.
+
+ * args.c (args_parse): Added -force-reinstall option to enable
+ reinstallation of an installed package.
+
+ * busybox-0.60.2/ar.c (ar_main): Updated unarchive call to track
+ prototype change.
+
+ * busybox-0.60.2/libbb/unarchive.c (free_header_ar): Added
+ function to plug memory leak.
+
+ * ipkg_install.c (check_data_file_clashes): Fixed crash if no
+ package can be found owning the pre-existing file.
+
+ * pkg_dest.c (pkg_dest_deinit): Fixed bug that pkg_dest was
+ holding on to freed data rather than making a local copy.
+
+ * pkg_depends.c (freeDepends): Fixed crash when pkg->depends is NULL.
+
+ * RELEASE_NOTES: Added release notes for 0.98.0 and 0.99.0.
+
+ * busybox-0.60.2/libbb/unarchive.c (extract_archive): Fixed
+ bug. Always alloc memory for full_name so we don't free data that
+ we shouldn't.
+ (unarchive): Updated to accept a free_headers function pointer as
+ a counterpart to get_headers, to eliminate memory leaks.
+ (free_header_tar): Implemented cleanup function as counterpart to
+ get_header_tar, to eliminate memory leaks.
+ (deb_extract): Added several calls to free_header_tar to eliminate
+ memory leaks.
+
+ * str_util.c (str_dup_safe): Added convenience function. Like
+ strdup, but safe to use on a NULL pointer.
+
+ * pkg_vec.c (pkg_vec_insert): Updated to use new pkg.c:pkg_merge
+ rather than marry_two_packages. With this change the free(pkg) is
+ now here rather than one level deeper. Eventually, I want to get
+ this free(pkg) up and out of pkg_hash_insert.
+
+ * pkg_parse.c (parseDependsString): Fixed bug walking off the end
+ of the raw buffer looking for a character that isspace().
+ (parseConffiles): Fixed big bug parsing Conffiles field where all
+ conffiles appear on the same line.
+
+ * pkg_hash.c (pkg_hash_add_from_file): Plugged memory leak of data
+ allocated deep down in read_raw_pkgs_from_file.
+
+ * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Plugged
+ memory leak, (missing pkg_vec_deinit).
+ (freeDepends): Added this function as the counterpart to
+ buildDepends. Getting closer to chasing down all memory leaks.
+ (depend_deinit): Added this function as the counterpart to
+ depend_init. Getting closer to chasing down all memory leaks.
+ (parseDepends): plugged memory leak of pkg_name.
+
+ * pkg.c (pkg_deinit): Added pkg_deinit to take care of freeing any
+ memory owned by a pkg_t.
+ (pkg_init_from_file): This function was 100% broken, (missing
+ rewind).
+ (pkg_merge): Moved pkg_merge here from
+ pkg_vec.c:marry_two_packages. Started work to make it
+ non-destructive, (not finished).
+ (pkg_print_info): Added Status and Essential fields to
+ pkg_print_info.
+ (pkg_print_status): Fixed pkg_print_status to work whether or not
+ the package is installed.
+
+ * ipkg_utils.c (read_raw_pkgs_from_file): Moved fclose out of
+ read_raw_pkgs_from_stream and into this function where it belongs,
+ (since the fopen occurs here).
+ (trim_alloc): Fixed trim to not free data passed in. Changed the
+ name to make it obvious that it is allocating memory.
+
+ * ipkg_install.c (ipkg_install_from_file): Fixed to be more robust
+ to the fact that hash_insert_pkg sometimes frees the data that I
+ pass into it (!).
+ (satisfy_dependencies_for): Cosmetic change to messages.
+ (satisfy_dependencies_for): Now sets the dest on to-be-installed
+ packages, so that the state_want flag can be written to a status
+ file if necessary.
+ (satisfy_dependencies_for): Added pkg_vec_deinit to plug memory
+ leak.
+ (ipkg_install_pkg): Added "run ipkg update?" hint to error
+ message.
+ (backup_modified_conffiles): Made more robust to the case that a
+ conffile has disappeared.
+ (install_maintainer_scripts): Fixed bug that was installing
+ maintainer scripts as libFoopostinst rather than
+ libFoo.postinst. This was preventing postinst scripts from being
+ executed.
+ (cleanup_temporary_files): Added missing closedir to plug a memory
+ leak.
+
+ * ipkg_download.c (ipkg_download): Cosmetic change to error
+ messages.
+
+ * ipkg_conf.c (ipkg_conf_parse_file): Plugged some small memory
+ leaks.
+ (ipkg_conf_set_option): Changed configuration options from
+ force-depends, force-defaults to force_depdends, force_defaults to
+ be compatible with old ipkg.conf files.
+ (ipkg_conf_set_option): Fixed bug in parsing options.
+ (ipkg_conf_write_status_files): Fixed to list all interesting
+ packages, (any with non-default state), in status file rather than
+ just installed files.
+ (ipkg_conf_write_status_files): Plugged a memory leak.
+
+ * ipkg_cmd.c (ipkg_status_cmd): Changed "ipkg status" to use
+ pkg_print_info so it is much more verbose, (includes fields such
+ as Maintainer, etc. that are merged in from the lists files).
+
+ * ipkg.h (IPKG_DEBUG_NO_TMP_CLEANUP): Added compile-time option to
+ preserve temporary files for easier debugging.
+
+ * file_util.c (file_md5sum_alloc): cosmetic changes to variable
+ names.
+
+ * ipkg_conf.c (ipkg_conf_init): Added support for offline_root
+ configuration file option.
+
+ * args.c (args_init): Added support for -o, -offline,
+ -offline-root command-line arguments. (Although they don't really
+ have any effect yet).
+
+ * ipkg_install.c (ipkg_install_pkg): Changed back to marking
+ package as installed before postinst, (the pkg_run_script wanted
+ to find the scripts in /usr/lib/ipkg/info). Actually, it could
+ probably find the script in either place at this point so maybe it
+ doesn't really matter.
+
+2002-03-07 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_install.c (ipkg_install_pkg): Changed to only mark package
+ as installed after running ipkg_configure, (to run the postinst
+ script).
+
+ * RELEASED ipkg-unstable 0.99.0
+
+ * Updated all instances of "XXX" in the code to indicate one of
+ the following categories:
+ XXX: BUG: This is a bug that needs to be fixed.
+ XXX: QUESTION: Implementation approach is uncertain here.
+ XXX: CLEANUP: Suggestion on how the code could be cleaned up.
+ XXX: FEATURE: Comment describes a useful feature request.
+
+ * pkg.c (pkg_print_status): Added the Depends field to package
+ paragraphs in the status file, ("ipkg remove" will need this).
+
+ * ipkg_install.c (satisfy_dependencies_for): Fixed "ipkg install"
+ to not complain several times about "Package foo already
+ installed" when doing large recursive installs.
+ (ipkg_install_pkg): "ipkg install foo" for an installed package
+ will now check and install any missing dependencies before exiting
+ with "Package foo is alrady installed."
+
+2002-03-06 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_dest.c (pkg_dest_pkg_owning_file_alloc): Moved this function
+ here from ipkg_install.c. Also plugged a memory leak in it with
+ globfree.
+
+ * pkg.c (pkg_remove_installed_files_list): Fixed bug that
+ prevented package.list file from ever being removed during "ipkg
+ remove".
+
+ * ipkg_remove.c (remove_data_files_and_list): Fixed noisy and
+ spurious warnings about non-empty directories. "ipkg remove"
+ should now only say anything if a directory that was solely
+ provided by that package is non-empty.
+
+ * ipkg_cmd.c (ipkg_install_pending_cmd): Plugged memory leak with
+ globfree.
+
+ * ipkg_install.c: *Many* fixes to enable "ipkg upgrade" to more or
+ less work. Primarily fixing file clash identification and conffile
+ handling/resolution. "ipkg upgrade" has now worked correctly on
+ several test cases!
+
+ * ipkg_install.c (unpack_pkg_control_files): Now initializes
+ conffiles list from the contents of conffiles control file,
+ (leaves md5sum calculation until the actual conffiles are
+ extracted later).
+ (ipkg_install_pkg): Separated backup_modified_conffiles and
+ check_data_file_clashes into separate functions.
+ (preinst_configure): Simplified this function pushing its old
+ logic into pkg.c:pkg_run_script.
+ (backup_modified_conffiles): Added backup of any conffiles that
+ are new as of this upgrade.
+ (check_data_file_clashes): First real implementation of
+ check_data_file_clashes.
+ (resolve_conffiles): First real implementation of
+ resolve_conffiles.
+ (backup_make_backup): Added this and a few other functions to
+ abstract backup creation/removal.
+ (find_pkg_owning_file): Added this function.
+
+ * pkg_extract.c (pkg_extract_data_files_to_dir): Fixed args to
+ deb_extract so that existing files will be overwritten, (and any
+ other error messages will no longer be suppressed).
+
+ * pkg.c (pkg_print_status): Added Conffiles field to
+ pkg_print_status.
+ (pkg_print_field): Fixed crash when printing NULL Conffiles
+ values.
+ (pkg_get_conffile): Fixed crash if pkg_get_conffile called with a
+ NULL pkg.
+ (pkg_run_script): Made pkg_run_script smart enough to run scripts
+ for uninstalled packages, (from
+ <pkg_tmp_unpack_dir>/<script_name>), as well as for isntalled
+ packages, (from <dest_info_dir>/<pkg_name>.<script_name>
+
+ * str_util.c (str_tolower): Added convenience function.
+ (str_toupper): Added convenience function.
+
+ * nv_pair.c (nv_pair_init): Fixed crash from calling nv_pair_init
+ with NULL value.
+
+ * pkg.c (pkg_init_from_file): Fixed bug -- forgot to close file.
+
+ * file_util.c (file_md5sum_alloc): Convenience wrapper around
+ md5_stream as ripped out of busybox. This function takes care of
+ file open/close and does the bin2hex conversion of the md5sum.
+
+ * conffile.c (conffile_has_been_modified): Implemented this
+ function for real now that we have md5sum capability.
+
+ * md5.c (md5_stream): Sucked in md5sum calculation code from
+ busybox, (it wasn't part of libbb, so I just copied the files
+ straight in and ripped out uninteresting functions such as
+ md5sum_main, etc.)
+
+2002-03-05 Carl Worth <cworth@east.isi.edu>
+
+ * pkg.c (pkg_print_field): Added support for printing Conffiles
+ field.
+
+ * ipkg_install.c (remove_obsolesced_files): With the fixed
+ pkg_get_installed_files_list from below, this function now seems
+ to work!
+ (ipkg_install_pkg): Fixed to mark old package as uninstalled after
+ upgrading.
+
+ * pkg.c (pkg_get_installed_files_list): Fixed so that it's
+ possible to get an "installed_files" list even from an uninstalled
+ package, (it pulls the list of data files straight out of the
+ package).
+
+ * ipkg_cmd.c (ipkg_upgrade_cmd): Fixed ipkg_upgrade to not choke
+ if asked to upgrade an un-installed package.
+ (ipkg_upgrade_pkg): Fixed printing of version numbers.
+
+ * file_util.c (file_mkdir_hier): Abstracted call to libbb
+ make_directory into new file_mkdir_hier. At this point, the only
+ calls into libbb are isolated in file_util and pkg_extract. This
+ will make it easier if we ever decide to directly incorporate that
+ code or rewrite it.
+
+ * pkg_extract.c (pkg_extract_data_files_to_dir): Abstracted all
+ calls to deb_extract in several new pkg_extract functions.
+
+2002-03-04 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_conf.c (ipkg_conf_init): Added support to ipkg_conf to
+ pickup command-line arguments for "force-defaults" and
+ "force-depends". Things set on the command-line should take
+ precedence over things found in the configuration file.
+
+ * ipkg_cmd.c (ipkg_search_cmd): Fixed formatting of "ipkg search"
+ output.
+
+ * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies):
+ Re-added fix to set *unresolved to NULL if depends is NULL.
+
+ * xregex.c (xregexec): Removed useless error messages from NOMATCH
+ calls to regexec.
+
+ * ipkg_install.c (satisfy_dependencies_for): Added support for new
+ "unresolved" argument in
+ pkg_hash_fetch_unsatisfied_dependencies. Cleaned up warning/error
+ messages.
+
+ * ipkg_cmd.c (ipkg_search_cmd): Implemented first-cut of "ipkg search".
+
+ * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Fixed
+ to set *unresolved to NULL if depends is NULL.
+
+2002-03-01 Carl Worth <cworth@east.isi.edu>
+
+ * RELEASED ipkg-unstable 0.98.0
+
+ * ipkg_configure.c (ipkg_configure): Added flushing of stdout,
+ (here and in a few other modules).
+
+ * file_util.c (file_copy): Implemented this function here as one
+ step toward isolating the calls into libbb functions. Updated old
+ copy_file calls to file_copy in both ipkg_download.c and
+ ipkg_install.c.
+
+ * ipkg_install.c, ipkg_remove.c: Demoted several "XXX" comments to
+ DPKG_INCOMPATIBILITY as I really don't intend on addressing them
+ any time soon, (if ever).
+
+ * ipkg_cmd.c (ipkg_files_cmd): Fixed "ipkg files" from crashing on
+ uninstalled packages.
+
+ * familiar/rules: Added support for easy building of an
+ ipkg.ipk. The version number and the architecture are
+ automatically sucked in correctly from autoconf magic, (even when
+ cross-compiling). Maybe autoconf will start paying off with
+ benefits rather than pain, (finally!).
+
+ * configure.ac: Removed MEMCMP and STAT checks which were breaking
+ cross-compilation.
+
+ * ipkg_cmd.c (ipkg_upgrade_pkg): BIG bugfix: Package version
+ comparison was sign-reversed, (hence it would never upgrade).
+
+2002-02-28 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_download.c (ipkg_download): Changed from
+ system("/bin/cp",...) to copy_file(...)
+
+ * replace/strndup.c: Implemented an (untested) replacement for
+ strndup.
+
+ * configure.ac: Added AC_CANONICAL_HOST to automatically set the
+ correct architecture type in the ipkg control file.
+
+ * configure.ac: Changed version number to 0.98.0 in preparation
+ for alpha release.
+
+ * familiar/rules: Added support for easy building of an ipkg.ipk.
+
+2002-02-27 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_install.c (ipkg_install_pkg): Fixed to abort on failed
+ download.
+
+ * pkg.c (pkg_run_script): Fixed bug that was preventing any
+ package maintainer scripts from running, (hence, they run now so
+ running non-native offline no longer works until I figure out the
+ chroot plans).
+
+ * TODO: Added rough outline of remaining features with a release
+ schedule.
+
+ * pkg_parse.c (pkg_parse_raw): Added parsing of "MD5Sum" in
+ addition to "MD5sum" to accomodate bug in old ipkg.
+
+ * void_list.c (void_list_remove): Added new remove function, (also
+ adjusts a forward iterator). Required new list->pre_head member
+ which was added to all sub-list types.
+
+ * pkg.c (pkg_init): Changed pkg->conffiles to be of the new
+ conffile_list_t datatype.
+ (pkg_remove_installed_files_list): Pulled this function into
+ pkg.c, (from ipkg_remove.c), so the mallocs and frees would be in
+ the same C file.
+ (pkg_get_conffile): Added this convenience function.
+
+ * ipkg_remove.c: Fixed several bugs. ipkg_remove now actually
+ works for simple packages!
+
+ * ipkg_install.c (ipkg_install_pkg): Don't re-install if a package
+ is already installed.
+ (ipkg_install_pkg): Fixed major bug that all of ipkg_install's
+ work was always being unwound even when successful.
+
+ * ipkg_cmd.c (ipkg_files_cmd): Fixed to use
+ pkg_get_installed_files_list rather than a private implementation
+ that sifted through the file lists on disk.
+
+ * str_util.c (str_ends_with): Added this convenient function.
+ (str_chomp): Another convenience.
+
+ * ipkg_conf.c: Moved chomp to str_util.c (str_chomp), since
+ someone else wanted it too.
+
+2002-02-26 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_parse.c (pkg_parse_raw): Added XXX requesting parsing of
+ Conffiles: field along with a hint about how to store the data.
+
+ * conffile_list.c: Added a little wrapper around nv_pair_list
+
+ * conffile.c: Added a little wrapper around nv_pair
+
+ * str_util.c (str_ends_with): New convenience function.
+
+ * str_list.c (str_list_remove): Plugged in remove function.
+
+ * void_list.c (void_list_remove): Added remove function, (handles
+ updating of forward iterator).
+
+ * pkg.c (pkg_run_script): Changed to return return value of
+ script.
+
+ * ipkg_remove.c: Fleshed out initial version of all ipkg_remove.c
+ functions.
+
+ * ipkg_configure.c (ipkg_configure): Added check on return value
+ of pkg_run script. Added comments about dpkg compliance.
+
+ * ipkg_cmd.c (ipkg_purge_cmd): Added ipkg_purge_cmd
+
+2002-02-20 Carl Worth <cworth@east.isi.edu>
+
+ * Added USC copyright statements, (and Compaq stubs as necessary)
+
+ * ipkg_install.c: At this point "ipkg install" on a simple
+ package, (no scripts and no dependencies), works just fine. It
+ might even do some of the script and dependency handling correctly
+ too, but I haven't tested that yet. "ipkg install libc6" is a nice
+ little test that should complete without any errors or
+ warnings. Follow that up with "ipkg status" to see that it worked.
+
+ * pkg.c (pkg_run_script): Added convenience method for running
+ package scripts.
+
+ * ipkg_install.c: Fixed several bugs:
+ (unpack_pkg_control_files): control files now extract to the
+ correct temporary directory.
+ (ipkg_install_pkg): pkg->state_want is now properly set to SW_INSTALL
+ (ipkg_install_pkg): status file now gets written after installation
+ (cleanup_temporary_files): All temporary files are cleaned up.
+
+ * ipkg_configure.c (ipkg_configure): Fleshed out a very simple
+ ipkg_configure, (simply runs "postinst configure"). Maybe it will
+ need to be smarter at some point. Moved unwritten conffiles stuff
+ back to ipkg_install.c.
+
+ * ipkg_conf.c (ipkg_conf_write_status_files): Moved this function
+ from ipkg_utils to ipkg_conf since it needs access to the
+ pkg_dest_list.
+
+ * pkg_vec.c (marry_two_packages): Added several missing fields,
+ (state_want, state_flag, filename, local_filename, tmp_unpack_dir,
+ md5sum, size, installed_size, priority, source, conffiles,
+ isntalled_files, essential)
+
+2002-02-19 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_install.c: several little bug fixes. "ipkg install" will
+ now actually install files from a package! There are still some
+ bugs, (eg. postinst scripts are not called -- probably other
+ things as well). But, it's coming together now.
+
+ * pkg_dest.c (pkg_dest_init): now creates all necessary directories
+
+ * ipkg_download.c (ipkg_download): Fixed misleading parameter name.
+
+ * ipkg_conf.c (ipkg_conf_deinit): Now cleans up tmd_dir on deinit
+ ipkg.c: now calls ipkg_conf_deinit before exiting.
+ (ipkg_conf_add_nv): Fixed to set default_dest when parsing first
+ dest in ipkg.conf
+
+ * ipkg_cmd.c (ipkg_list_cmd): Fixed ugly bug in ipkg_list that led
+ to infinite loops, segfaults, string corruption, and other bizarre
+ behavior.
+
+ * Added many files as we are approaching the first functional ipkg
+ implementation in C:
+ file_util.c: convenience for testing if file_exists, reading files, etc.
+ ipkg_configure.c: mostly just a stub so far
+ ipkg_download.c: convenient function to download a file
+ nv_pair.c: data structure to hold a name-value pair
+ nv_pair_list.c: data structure to hold a list of nv_pair_t
+ pkg_dest.c: data structure for everything a pkg destination wants
+ pkg_dest_list.c: data structure to hold a list of pkg_dest_t
+ pkg_extract.c: convenience functions for package extraction,
+ (these function should encapsulate any libbb borrowings we perform
+ -- although some slipped into other files already)
+ pkg_src.c: everything you might need for a pkg src.
+ pkg_src_list.c: data structure to hold a list of pkg_src_t
+ str_list.c: data structure to hold a list of char *
+ void_list.c: generic linked-list data structure and functions
+ xsystem.c: wrapper around system() with error checking
+
+ * ipkg_remove.c: Just added some stubs. Nothing really works at
+ all yet.
+
+ * ipkg_install.c: Large rework of ipkg_install. It's now close to
+ actually being usable, (but it's not quite there yet). Revamped to
+ match dpkg install order more closely, (with all the stubs in case
+ we ever want to call all the scripts that dpkg does). Also updated
+ to use a more recent deb_extract from libbb.
+
+ * ipkg_extract_test.c (main): Added support for a third arg, (the
+ filename to extract to the buffer).
+
+ * ipkg_conf.c (ipkg_conf_init): Added several fields to
+ ipkg_conf_t: pkg_src_list, pkg_dest_list ,
+ restrict_to_default_dest, default_dest, tmp_dir, lists_dir,
+ pending_dir, force_depends, and pkg_hash. There's still a bit of
+ tension between options stored in the config file, (ipkg_conf_t),
+ and command-line arguments, (args_t).
+
+ * ipkg_cmd.c: First version that is approaching usability. The
+ following commands are more-or-less in place: "ipkg update", "ipkg
+ list", "ipkg info", "ipkg status". While the rest are in various
+ states of being partiallyy written or written but untested.
+ (ipkg_upgrade_cmd): Added support for restricting to a dest. Many
+ other changes, largely involving plugging into the pkg_hash for
+ real for the first time, and adding multiple dest support.
+
+ * ipkg.c: Added support for setting the dest on the command-line.
+
+ * args.c: Added support for IPKG_CONF_DIR environment variable and
+ -f, -conf, and -conf-file options.
+
+ * configure.ac: Added lots of little bits suggested by autoscan.
+
+2002-02-18 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_parse.c (pkg_parse_raw): Added parsing, (kinda ugly), for
+ essential field.
+ * pkg.c (pkg_print_field): Added the essential flag.
+
+ * pkg_vec.c (pkg_vec_insert): Fixed to use pkg_compare_versions to
+ determine matching versions instead of a strcmp on the version
+ string.
+
+2002-02-15 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_parse.c (pkg_parse_raw): Updated to accept a pkg_src_t
+
+ * pkg.c (pkg_init): Added field to pkg_t: "pkg_src_t *src"
+
+ * pkg_hash.c (pkg_hash_add_from_file): Updated to accept a pkg_src_t
+
+ * pkg_parse.c (parseStatus): Modified to accept a pkg_t *
+ (parseVersion): Added this function
+ (pkg_parse_raw): Updated to accept a pkg_dest_t
+ (pkg_parse_raw): Reworked the parsing to use a pkg_t rather than a
+ slew of local variables.
+ (pkg_parse_raw): Added support for about a dozen new pkg_t fields
+
+ * pkg.h: Updated for all pkg.c changes.
+
+ * pkg.c (pkg_new): Added pkg_new for convenient alloc'ing of a pkg_t.
+ (pkg_init): Added several fields to pkg_t: dest, section,
+ suggests, filename, local_filename, tmp_unpack_dir, md5sum, size,
+ installed_size, priority, source, and conffiles.
+ (): Moved buildPkg this function to pkg_parse
+ (pkg_init_from_file): Added convenience function for filling a
+ pkg_t from an actual package file.
+ (pkg_print_info): Split print_pkg into both pkg_print_info and
+ pkg_print_status.
+ (pkg_print_field): Added pkg_print_field, (extremely ugly)
+ (): Moved parseversion to pkg_parse where it belongs
+ (pkg_version_str_alloc): Added, (complement of parse_version)
+
+ * pkg_depends.h: Added GPL blurb
+ (PKG_DEPENDS_H): Added multiple include protection
+
+ * pkg_depends.c: Moved non-static prototypes to header file.
+ Changed several locl-only functions to be static.
+ Added function prototypes for static functions.
+ (buildDepends): Removed unecessary cast of malloc return value.
+
+ * pkg_hash.h: Moved hash-related struct declarations to this file
+ Rename pkg_fetch* to have consistent pkg_hash_fetch prefix.
+ Added missing prototype for pkg_vec_fetch_by_name
+
+ * pkg_hash.c: (pkg_hash_add_from_file): Added support for setting
+ the pkg_dest
+ (pkg_hash_add_from_file): Moved buildDepends call to
+ hash_insert_pkg
+ (pkg_hash_fetch_installed_by_name_dest): Added this function to
+ support pkg_dest
+
+ * ipkg_utils.h: Added GPL blurb
+ (IPKG_UTILS_H): Added multiple include protection
+
+ * ipkg_utils.c:
+ (read_raw_pkgs_from_file): broke read_raw_pkgs into
+ read_raw_pkgs_from_file and read_raw-pkgs_from_stream
+ (ipkg_write_status_file): Fixed return value
+ (print_pkg_status): Moved this function to pkg.c:pkg_print_status
+ (line_is_blank): Fixed const char handling
+
+2002-02-08 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_parse.c: Fixed a bug in parsing the 3 state fields.
+
+2002-02-06 Carl Worth <cworth@east.isi.edu>
+
+ * pkg.c: Expanded pkg_status field to the full 3 fields: state_want,
+ state_flag, and state_status.
+
+2001-12-11 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_conf.c: Now parses /etc/ipkg.conf, (and doesn't do anything
+ with it).
+
+ * ipkg.c: Started work on ipkg main, (not much here yet).
+
+ * ipkg_cmd.h: Added a tiny thing to abstract top-level ipkg
+ commands, (not finished).
+
+ * Set up autoconf and friends
diff --git a/src/.svn/text-base/ChangeLog.svn-base b/src/.svn/text-base/ChangeLog.svn-base
new file mode 100644
index 0000000..e6cd338
--- /dev/null
+++ b/src/.svn/text-base/ChangeLog.svn-base
@@ -0,0 +1 @@
+Please see svn log :/
diff --git a/src/.svn/text-base/INSTALL.svn-base b/src/.svn/text-base/INSTALL.svn-base
new file mode 100644
index 0000000..3350a01
--- /dev/null
+++ b/src/.svn/text-base/INSTALL.svn-base
@@ -0,0 +1,196 @@
+opkg uses autoconf and friends for configuration. The familiar steps of:
+
+ ./configure
+ make
+
+should be sufficient, (you may need an initial ./autoconfigure.sh), if
+you don't have a generated configure script, (ie. you're compiling a
+version out of CVS).
+
+The remainder of this document is the standard INSTALL document
+provided by autoconf.
+
+-Carl <cworth@handhelds.org>
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/src/.svn/text-base/Makefile.am.svn-base b/src/.svn/text-base/Makefile.am.svn-base
new file mode 100644
index 0000000..26f2d99
--- /dev/null
+++ b/src/.svn/text-base/Makefile.am.svn-base
@@ -0,0 +1,37 @@
+ACLOCAL_AMFLAGS = -I shave
+
+SUBDIRS = libbb libopkg src tests utils man
+
+
+HOST_CPU=@host_cpu@
+BUILD_CPU=@build_cpu@
+OPKGLIBDIR=@opkglibdir@
+ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DDATADIR=\"@datadir@\"
+
+PATHFINDER_CFLAGS = @PATHFINDER_CFLAGS@
+PATHFINDER_LIBS = @PATHFINDER_LIBS@
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libopkg.pc
+
+
+
+interceptdir = $(datadir)/opkg/intercept
+intercept_DATA = intercept/ldconfig intercept/depmod intercept/update-modules
+
+install-data-hook:
+ chmod +x $(DESTDIR)$(datadir)/opkg/intercept/*
+
+EXTRA_DIST = $(intercept_DATA)
+
+MAINTAINERCLEANFILES= \
+ configure \
+ Makefile.in \
+ config.guess \
+ config.sub \
+ ltmain.sh \
+ .Makefile.am.swp \
+ aclocal.m4
+
+package: all-recursive
+ STRIPPROG=$(STRIP) INSTALL=$$PWD/install-sh binary-arch
diff --git a/src/.svn/text-base/NEWS.svn-base b/src/.svn/text-base/NEWS.svn-base
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/.svn/text-base/NEWS.svn-base
diff --git a/src/.svn/text-base/README.svn-base b/src/.svn/text-base/README.svn-base
new file mode 100644
index 0000000..cf20f1f
--- /dev/null
+++ b/src/.svn/text-base/README.svn-base
@@ -0,0 +1,12 @@
+OPKG Package Management System
+==============================
+
+Opkg is a lightweight package management system based on Ipkg.
+
+Website: http://code.google.com/p/opkg/
+Mailing list: http://groups.google.com/group/opkg-devel
+Bug tracker: http://code.google.com/p/opkg/issues/list
+
+The previous website can still be found at:
+http://wiki.openmoko.org/wiki/Opkg
+
diff --git a/src/.svn/text-base/TODO.svn-base b/src/.svn/text-base/TODO.svn-base
new file mode 100644
index 0000000..0777b1c
--- /dev/null
+++ b/src/.svn/text-base/TODO.svn-base
@@ -0,0 +1,42 @@
+
+See issue list: http://code.google.com/p/opkg/issues/list
+
+
+ * Regression test suite.
+
+ * Fix comments marked "XXX".
+
+ * Clean up out of date comments.
+
+ * Consistent indentation.
+
+ * Propagate errors up the call stack. In particular, unarchive.c fails to do
+ this. Errors and error messages must be usable by libopkg frontends.
+ Don't try to use errno after its been clobbered by other libc calls.
+
+ * Remove dead and duplicate code. Refactor duplicated functionality.
+
+ * Remove pkg_info_preinstall_check().
+
+ * Reduce memory used per pkg_t and peak memory use in general.
+
+ * #includes are a mess.
+
+ * Refactor opkg_install_pkg() into more precise functions.
+
+ * pkg_hash_fetch_best_installation_candidate() is linear search O(P*PN)
+ and is slow (frequently called).
+ P provider
+ PN pkgs in a provider
+ It can be O(P) if a hash table is used.
+
+ * Update libbb.
+
+
+
+FEATURES
+
+ * Start with all "XXX: FEATURE" comments. Remove them if they are bogus.
+
+ * Improve dpkg compatibility, according to the Debian Policy Manual.
+ http://www.debian.org/doc/debian-policy/ch-controlfields.html
diff --git a/src/.svn/text-base/autogen.sh.svn-base b/src/.svn/text-base/autogen.sh.svn-base
new file mode 100644
index 0000000..95b5fba
--- /dev/null
+++ b/src/.svn/text-base/autogen.sh.svn-base
@@ -0,0 +1,5 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+glib-gettextize --force --copy || exit 1
+./configure "$@"
+
diff --git a/src/.svn/text-base/configure.ac.svn-base b/src/.svn/text-base/configure.ac.svn-base
new file mode 100644
index 0000000..ac5a035
--- /dev/null
+++ b/src/.svn/text-base/configure.ac.svn-base
@@ -0,0 +1,297 @@
+# Process this file with autoconf to produce a configure script
+AC_INIT([opkg], [0.1.8])
+AC_CONFIG_SRCDIR([libopkg/pkg.c])
+
+AC_CONFIG_AUX_DIR([conf])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_MACRO_DIR([shave])
+
+AM_INIT_AUTOMAKE
+AM_CONFIG_HEADER(libopkg/config.h)
+
+AC_CANONICAL_HOST
+AC_GNU_SOURCE
+
+# Disable C++/Fortran checks
+define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])
+define([AC_LIBTOOL_LANG_F77_CONFIG], [:])
+
+
+for top_builddir in . .. ../.. $ac_auxdir $ac_auxdir/..; do
+ test -f $top_builddir/configure && break
+done
+
+# large file support can be useful for gpgme
+AC_SYS_LARGEFILE
+
+
+# Checks for programs
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AM_PROG_INSTALL_STRIP
+AC_PROG_LIBTOOL
+PKG_PROG_PKG_CONFIG([0.20])
+
+# Checks for libraries
+
+dnl extra argument: --enable-pathfinder
+AC_ARG_ENABLE(pathfinder,
+ AC_HELP_STRING([--enable-pathfinder], [Enable libpathfinder support.
+ [[default=no]] ]),
+ [want_pathfinder="$enableval"], [want_pathfinder="no"])
+dnl Check for libpathfinder
+if test "x$want_pathfinder" = "xyes"; then
+ PKG_CHECK_MODULES([PATHFINDER], [pathfinder-openssl dbus-1 openssl])
+ if test -n "$PATHFINDER_CFLAGS$PATHFINDER_LIBS"; then
+ AC_DEFINE(HAVE_PATHFINDER, 1, [we have pathfinder])
+ fi
+ AC_SUBST(PATHFINDER_CFLAGS)
+ AC_SUBST(PATHFINDER_LIBS)
+fi
+AM_CONDITIONAL(HAVE_PATHFINDER, test "x$want_pathfinder" = "xyes")
+
+# check for libcurl
+AC_ARG_ENABLE(curl,
+ AC_HELP_STRING([--enable-curl], [Enable downloading with curl
+ [[default=yes]] ]),
+ [want_curl="$enableval"], [want_curl="yes"])
+
+if test "x$want_curl" = "xyes"; then
+ PKG_CHECK_MODULES(CURL, [libcurl])
+ AC_DEFINE(HAVE_CURL, 1, [Define if you want CURL support])
+fi
+
+# check for sha256
+AC_ARG_ENABLE(sha256,
+ AC_HELP_STRING([--enable-sha256], [Enable sha256sum check
+ (sha256.{c,h} are GPLv3 licensed) [[default=no]] ]),
+ [want_sha256="$enableval"], [want_sha256="no"])
+
+if test "x$want_sha256" = "xyes"; then
+ AC_DEFINE(HAVE_SHA256, 1, [Define if you want sha256 support])
+fi
+AM_CONDITIONAL(HAVE_SHA256, test "x$want_sha256" = "xyes")
+
+# check for openssl
+AC_ARG_ENABLE(openssl,
+ AC_HELP_STRING([--enable-openssl], [Enable signature checking with OpenSSL
+ [[default=no]] ]),
+ [want_openssl="$enableval"], [want_openssl="no"])
+
+if test "x$want_openssl" = "xyes"; then
+ AC_DEFINE(HAVE_OPENSSL, 1, [Define if you want OpenSSL support])
+ NEED_SSL_LIBS="yes"
+fi
+
+# check for libssl-curl
+AC_ARG_ENABLE(ssl-curl,
+ AC_HELP_STRING([--enable-ssl-curl], [Enable certificate authentication with curl
+ [[default="yes"]] ]),
+ [want_sslcurl="$enableval"], [want_sslcurl="yes"])
+
+if test "x$want_curl" = "xyes" -a "x$want_sslcurl" = "xyes"; then
+ AC_DEFINE(HAVE_CURL, 1, [Define if you want CURL support])
+ AC_DEFINE(HAVE_SSLCURL, 1, [Define if you want certificate authentication with curl])
+ NEED_SSL_LIBS="yes"
+fi
+
+if test "x$NEED_SSL_LIBS" = "xyes"; then
+ AC_MSG_CHECKING([if openssl is available])
+
+ PKG_CHECK_MODULES(OPENSSL, openssl, [:], [:])
+ if test "x$OPENSSL_LIBS" != "x"; then
+ AC_MSG_RESULT(yes)
+ else
+ OPENSSL_LIBS="-lcrypto -lssl"
+ dnl If pkg-config fails, run compile/link test.
+ AC_TRY_LINK([
+#include <openssl/opensslv.h>
+], [
+return OPENSSL_VERSION_NUMBER; ],
+ [
+ AC_MSG_RESULT(yes)
+
+ ], [
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR(OpenSSL not found)
+ ])
+ fi
+ AC_SUBST(OPENSSL_LIBS)
+fi
+
+
+dnl **********
+dnl GPGME
+dnl **********
+
+AC_ARG_ENABLE(gpg,
+ AC_HELP_STRING([--enable-gpg], [Enable signature checking with gpgme
+ [[default=yes]] ]),
+ [want_gpgme="$enableval"], [want_gpgme="yes"])
+
+if test "x$want_gpgme" = "xyes"; then
+ ok="no"
+ min_gpgme_version=1.0.0
+ AC_PATH_PROG(GPGME_CONFIG, gpgme-config, "failed")
+ if test $GPGME_CONFIG != "failed" ; then
+ AC_MSG_CHECKING(for GPGME - version >= $min_gpgme_version)
+ req_major=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ req_minor=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ req_micro=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ gpgme_config_version=`$GPGME_CONFIG --version`
+ major=`echo $gpgme_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
+ minor=`echo $gpgme_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
+ micro=`echo $gpgme_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
+
+ if test "$major" -eq "$req_major"; then
+ if test "$minor" -ge "$req_minor"; then
+ if test "$micro" -ge "$req_micro"; then
+ ok="yes"
+ fi
+ fi
+ fi
+ fi
+
+ if test $ok = "yes"; then
+ GPGME_CFLAGS=`$GPGME_CONFIG --cflags`
+ GPGME_LIBS=`$GPGME_CONFIG --libs`
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_GPGME, 1, [Define if you want GPG support])
+ else
+ AC_MSG_ERROR(GPGME $min_gpgme_version or later needed)
+ fi
+fi
+
+AC_SUBST(GPGME_CFLAGS)
+AC_SUBST(GPGME_LIBS)
+
+
+# Checks for header files
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS([errno.h fcntl.h memory.h regex.h stddef.h stdlib.h string.h strings.h unistd.h utime.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_UID_T
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_CHECK_MEMBERS([struct stat.st_rdev])
+
+# Checks endianness
+AC_C_BIGENDIAN(BIGENDIAN_CFLAGS="-DWORDS_BIGENDIAN=1",)
+AC_SUBST(BIGENDIAN_CFLAGS)
+
+# Don't do annoying tests that don't work when cross-compiling, just trust them.
+# The AC_FUNC_MEMCMP test doesn't work during a cross-compile, disable.
+# AC_FUNC_MEMCMP
+# The AC_FUNC_STAT test doesn't work during a cross-compile, disable.
+# AC_FUNC_STAT
+
+# Checks for library functions
+AC_FUNC_CHOWN
+AC_FUNC_FORK
+AC_TYPE_SIGNAL
+AC_FUNC_UTIME_NULL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS([memmove memset mkdir regcomp strchr strcspn strdup strerror strndup strrchr strstr strtol strtoul sysinfo utime])
+
+opkglibdir=
+AC_ARG_WITH(opkglibdir,
+[ --with-opkglibdir=DIR specifies directory to put status and info files.
+ "/opkg" is always added so if you want your files
+ to be in /var/lib/opkg instead of /usr/lib/opkg
+ you should indicate
+ --with-opkglibdir=/var/lib ],
+[case "${withval}" in
+yes) AC_MSG_ERROR(bad value ${withval} given for opkg libs directories ) ;;
+no) ;;
+*) opkglibdir=$with_opkglibdir ;;
+esac])
+
+# Default local prefix if it is empty
+if test x$opkglibdir = x; then
+ opkglibdir=/usr/lib
+fi
+
+opkgetcdir=
+AC_ARG_WITH(opkgetcdir,
+[ --with-opkgetcdir=DIR specifies directory for opkg.conf file,
+ "/opkg" is always added so if you want your files
+ to be in /usr/etc/opkg instead of /etc/opkg
+ you should indicate
+ --with-opkgetcdir=/usr/etc ],
+[case "${withval}" in
+yes) AC_MSG_ERROR(bad value ${withval} given for opkg.conf directory ) ;;
+no) ;;
+*) opkgetcdir=$with_opkgetcdir ;;
+esac])
+
+# Default local prefix if it is empty
+if test x$opkgetcdir = x; then
+ opkgetcdir=/etc
+fi
+
+opkglockfile=
+AC_ARG_WITH(opkglockfile,
+[ --with-opkglockfile=FILE specifies the file used to make sure there is only
+ one instance of opkg runnning.
+ Defaults to ${opkglibdir}/opkg/lock, i.e.
+ /usr/lib/opkg/lock ],
+[case "${withval}" in
+yes) AC_MSG_ERROR(bad value ${withval} given for opkg lock file ) ;;
+no) ;;
+*) opkglockfile=$with_opkglockfile ;;
+esac])
+
+# Default if empty
+if test x$opkglockfile = x; then
+ opkglockfile=${opkglibdir}/opkg/lock
+fi
+
+dnl Some special cases for the wow64 build
+if test "x$want_gpgme" = "xyes"
+then
+ if test "x$want_openssl" = "xyes"
+ then
+ AC_MSG_ERROR([--enable-gpg and --enable-openssl are mutually exclusive.
+Use --disable-gpg if you want OpenSSL smime signatures])
+ fi
+fi
+
+CLEAN_DATE=`date +"%B %Y" | tr -d '\n'`
+
+AC_SUBST(opkglibdir)
+AC_SUBST(opkgetcdir)
+AC_SUBST(opkglockfile)
+AC_SUBST([CLEAN_DATE])
+
+# Setup output beautifier.
+SHAVE_INIT([shave], [enable])
+
+AC_OUTPUT(
+ Makefile
+ libopkg/Makefile
+ tests/Makefile
+ src/Makefile
+ libbb/Makefile
+ utils/Makefile
+ utils/update-alternatives
+ libopkg.pc
+ shave/shave
+ shave/shave-libtool
+ man/Makefile
+ man/opkg-cl.1
+ man/opkg-key.1
+ )
diff --git a/src/.svn/text-base/libopkg.pc.in.svn-base b/src/.svn/text-base/libopkg.pc.in.svn-base
new file mode 100644
index 0000000..25fe6e9
--- /dev/null
+++ b/src/.svn/text-base/libopkg.pc.in.svn-base
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: libopkg
+Description: opkg package manager library
+Version: @VERSION@
+Libs: -L${libdir} -lopkg
+Cflags: -I${includedir}/libopkg
+
diff --git a/src/AUTHORS b/src/AUTHORS
new file mode 100644
index 0000000..e7ce307
--- /dev/null
+++ b/src/AUTHORS
@@ -0,0 +1,8 @@
+Opkg:
+ * Thomas Wood <thomas@openedhand.com>
+ * Tick Chen <ticktock35@gmail.com>
+ * Graham Gower <graham.gower@gmail.com>
+Ipkg:
+ * Pierluigi Frullani <pigi@frumar.it>
+ * Carl Worth <cworth@handhelds.org>
+ * Steve Ayer <steven.ayer@compaq.com>
diff --git a/src/CONTRIBUTORS b/src/CONTRIBUTORS
new file mode 100644
index 0000000..d85411a
--- /dev/null
+++ b/src/CONTRIBUTORS
@@ -0,0 +1,31 @@
+=== Contributors ===
+
+The following people have submitted changes which have been applied to the
+core:
+
+Christopher Hall <hsw@openmoko.com>
+EdorFaus <edorfaus@gmail.com>
+Graham Gower <graham.gower@gmail.com>
+Krzysztof Kotlenga <pocek@users.sf.net>:
+Per Hansen <spamhans@yahoo.de>
+Mike Westerhof <mwester@dls.net>
+Antonio Ospite <ospite@studenti.unina.it>
+Koen Kooi <koen@beagleboard.org >
+Claudio Mignanti <claudyus84@gmail.com>
+Florian Boor <florian.boor@kernelconcepts.de>
+Camille Moncelier <moncelier@devlife.org>
+Jim Huang <jserv.tw@gmail.com>
+John L. Chmielewski <jlcster@gmail.com>
+
+
+== We don't have your name / email ==
+Gilles Doffe
+cconroy
+chgros
+Kosmaty
+manitu
+pblack88@gmail.com
+
+and anyone else who has sent patches or bug reports. If your name isn't on this
+list, please forgive us and send an email to a maintainer
+The project owners/committers is here: http://code.google.com/p/opkg/
diff --git a/src/COPYING b/src/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/src/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/ChangeLog b/src/ChangeLog
new file mode 100644
index 0000000..e6cd338
--- /dev/null
+++ b/src/ChangeLog
@@ -0,0 +1 @@
+Please see svn log :/
diff --git a/src/ChangeLog.ipkg b/src/ChangeLog.ipkg
new file mode 100644
index 0000000..5b86406
--- /dev/null
+++ b/src/ChangeLog.ipkg
@@ -0,0 +1,1761 @@
+2006-05-30 pigi ( pigi@frumar.it)
+ * Version update to 0.99.163
+ * Fixed a bug in GNU_TAR_EXTENSION of unarchive.c. This fix #1666
+
+2006-05-04 pigi ( pigi@frumar.it)
+ * Fixed a little bug in makefile that inhibit the compilation from .tar.gz ( missing intercept dir )
+
+2006-04-20 pigi ( pigi@frumar.it)
+ * Version update to 0.99.162
+ * Fixed a bad bug introduced in .160 that was blocking the install of a package
+
+2006-04-18 pigi ( pigi@frumar.it)
+ * Version update to 0.99.161
+
+2006-04-18 pigi ( pigi@frumar.it)
+ * Another little fix for the upgrade part.Now alse the prerm and postrm scripts gets deleted before upgrading.
+ wishing this fix the last troubles in upgrade part.
+ * Fix for #1585 after the bug introduced with the modify for offline root. ( Again )
+
+2006-03-30 pigi ( pigi@frumar.it)
+ * Activated the patch from Gunter@ohrner.net for the md5 check of package
+ * Another change in the upgrade part, to handle the ghosts files from an upgraded package
+
+2006-03-30 pigi ( pigi@frumar.it)
+ * Version update to 0.99.160
+ * Fix for #1585 after the bug introduced with the modify for offline root.
+ * Patch from Gunter@ohrner.net that fix a memory leak
+ * Not yet activated, but inserted a patch from Gunter@ohrner.net for the md5 check of package
+
+2006-02-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.159
+ * Another change in the upgrade part, to handle the ghosts files from an upgraded package
+ * Now it should be ok. Thanks to pb_ for pointing out where to look at.
+
+2006-02-02 pigi ( pigi@frumar.it)
+ * Version update to 0.99.158
+ * Modified the way upgrade handle the removing of a package, to be sure that ipkg doesn't break busybox upgrade
+ * this should fix #1503
+
+2006-01-30 pigi ( pigi@frumar.it)
+ * applied patch from pb_ for speed up things in boot ( to avoid multiple configure execution )
+ * applied patch from <r.schwebel@pengutronix.de> for 100+ filenames in tar file ( again )!
+ * applied patch from <r.schwebel@pengutronix.de> to avoid trouble in offlineroot installations.
+
+2006-01-22 pigi ( pigi@frumar.it)
+ * Version update to 0.99.157
+
+2006-01-17 pigi ( pigi@frumar.it)
+ * Added a check to avoid reading feed files with several options. This should fix #1458 and speed up a lot of executions.
+
+2006-01-12 pigi ( pigi@frumar.it)
+ * Version update to 0.99.156
+ * Fixed a length problem for strncpy when "Installing" option added. This fix bug #1456. Thanks to hrw for signaling
+
+2005-12-15 pigi ( pigi@frumar.it)
+ * Version update to 0.99.155
+ * Added a function to remove the package that is being upgraded.
+ * Fixed a problem when installing by hand. Now ipkg knows that a package has been selected by hand,
+ * and, if every check returns ok, it install the wanted package, instead of selecting one from feed.
+ * Moreover, now downgrade should works again.
+ * Fixed the "Replaces" bug. Now ipkg is able to replace a package also if it doesn't conflict.
+ * Other minor changes in debug options
+
+2005-09-15 pigi ( pigi@frumar.it)
+ * Version update to 0.99.154
+ * Corrected a problem when removing a package, caused by an off by one alignement with the "Provides:" String
+ * Patched for the "depends:" bug introduced after the "Provides:" fix. This fix #1393
+ * Added a little fix for an off-by-one error in checking for depends.
+
+2005-07-29 pigi ( pigi@frumar.it)
+ * Applied a patch for the GNU tar compatibility . Now ipkg can handle filenames > 100 char.
+
+2005-07-29 pigi ( pigi@frumar.it)
+ * Version update to 0.99.153
+ * Fixed a problem with Provides:. Now ipkg is able to install foo when foo is provided by bar, and is able to determine the best candidate based on
+ * package name. This also fix #1328
+
+2005-07-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.152
+ * Fixed a length problem for strncpy after "Downgrading" option added. This fix bug #1373. Thanks to steven.scholz@imc-berlin.de for signaling
+
+2005-06-16 pigi ( pigi@frumar.it)
+ * Version update to 0.99.151
+ * Fixed a missing check for null pointers . This fix bug #1358
+
+2005-06-05 pigi ( pigi@frumar.it)
+ * Version update to 0.99.150
+ * Added the -force-downgrade option to allow the downgrade of a package
+
+2005-05-11 pigi ( pigi@frumar.it)
+ * Version update to 0.99.149
+ * Added the possibility to choice the ipkglibdir from configure ( --with-libipkgdir )
+
+2005-04-10 pigi ( pigi@frumar.it)
+ * Version update to 0.99.148
+
+2005-04-09 pigi ( pigi@frumar.it)
+ * Found a bug in output from error_list. Now every error is printed, also if the functions don't return an error.
+ * Added a patch to Makefile from Robert Schwebel <r.schwebel@pengutronix.de>, cleaning things a bit. Thanks to Schwebel
+
+2005-03-30 pigi ( pigi@frumar.it)
+ * Version update to 0.99.147
+ * Found a bug in ipkg_install when freeing a cursor
+
+2005-03-28 pigi ( pigi@frumar.it)
+ * Version update to 0.99.146
+ * Modified the ipkg_error messaging to collect all the messages at the end of the program
+
+2005-03-26 pigi ( pigi@frumar.it)
+ * Little bug in message when "depends broken"
+
+2005-03-14 pigi ( pigi@frumar.it)
+ * Version update to 0.99.145
+ * Found a bug in ipkg remove when a package was depending in itself and ipkg where asked to "-recursive"
+ This fix bug # 1301
+ * A very little beautify in args.c
+
+2005-03-07 pigi ( pigi@frumar.it)
+ * Added the check for md5 in resolv_conf_file. Now ipkg ask for confirmation only it the files differ
+
+2005-02-22 pigi ( pigi@frumar.it)
+ * Version update to 0.99.144
+ * A little fix suggested by drw in ipkg_conf.c
+ * Changed the ipkg.h to be build in automake for oe mechanism . This will enhance the building phase
+ by honouring the lib hierarchy choose by users
+ * Changes in automake to honour the new building mechanism
+
+2005-02-20 pigi ( pigi@frumar.it)
+ * Version update to 0.99.143
+ * libipkg.h: reverting the previous modify
+ * ipkg_conf.c: fixing a probable bug in list_dir that fix problems with opie-packagemanager ( tanks to drw for signaling)
+
+2005-02-20 pigi ( pigi@frumar.it)
+ * libipkg.h: added some define to fix the broken external interface after 0.99.139 and lists_dir
+
+2005-02-17 pigi ( pigi@frumar.it)
+ * pkg_depends.c: applied patch from rjt@cambridgebroadband.com to remove some c99ism
+
+2005-02-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.142
+ * Fixed the definition of full_write and full_read as per bug #1280
+
+2005-02-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.141
+ * Added space in ipkg_message to give more readible messages
+ * Corrected a problem when creating the directories in pkg_dest_init
+
+2005-02-05 pigi ( pigi@frumar.it)
+ * Version update to 0.99.140
+ * Fixed the bug in ipkg_conf for a wrong pointer.
+
+2005-02-05 pigi ( pigi@frumar.it)
+ * Version update to 0.99.139
+ * Fixed the "replaces" problem reported by pb_. Now ipkg is able to resolve a "replace/conflict" reference
+ * Added the possibility to keep the lists file in a different location. Fullfill enh #1276
+
+2005-02-02 pigi ( pigi@frumar.it)
+ * Fixed the problem for SW_DEINSTALL in remove. Fix #1274
+ * Fixed the problem issued from florian. This also fix the bug #520 HardLink are now supported
+
+2005-01-18 pigi ( pigi@frumar.it)
+ * Version update to 0.99.138
+ * libbb.h: patch for the uclib
+
+2005-01-14 pigi ( pigi@frumar.it)
+ * ipkg_install.c: applied patch from rjt@cambridgebroadband.com to remove some c99ism
+
+2005-01-14 jamey ( jamey@handhelds.org )
+ * pkg_hash.c: applied patch from Jean Tourrilhes to allow default
+ arch to be different than host arch
+
+2005-01-10 pigi ( pigi@frumar.it)
+ * Version update to 0.99.137
+ * fixed a little, but annoying bug when writing the status file.
+
+2005-01-10 pigi ( pigi@frumar.it)
+ * Version update to 0.99.136
+ * Lot of memory leak fixes from Benjamin Pineau <ben@zouh.org>
+ * Fix for the Provides, that weren't able to "protect" their dependants while removing.
+ Now the remove should be safer.
+ * removed the replace.h stuff from automake .ac/.in files. This should align to oe
+
+2005-01-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.135
+ * Various fix for dependencies in control files
+
+2005-01-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.134-1 for fixing a problem with cvs tag on previous version
+
+2005-01-06 pigi ( pigi@frumar.it)
+ * Version update to 0.99.134
+ * Added a new option for listing only the installed packages. Asked by pb_ but really important
+ * Little modification to autoconfigure.sh
+ * removed fileutils dependencies that has disappeared from 0.8 in control-cl.in control-unstripped.in libipkg-control.in
+
+2004-11-18 pigi ( pigi@frumar.it)
+ * Version update to 0.99.133
+ * Fix for preserve date and time when extracting a package. Thanks to <trevor.pering@intel.com>
+
+2004-10-07 pigi ( pigi@frumar.it)
+ * Version update to 0.99.132
+ * Little fix on available blocks calculation. Thanks to seved.torstendahl@netinsight.se for founding it.
+ * this fix #1259
+
+2004-09-20 pigi ( pigi@frumar.it)
+ * Version update to 0.99.131
+ * Added a lot of debug info in DEBUG2
+ * Added a check in ipkg_install.c to permit replacing of existing file when installing a package
+ * from a file ( not an upgrade ) when ipkg find a file clash but the owner of the package is the
+ * same. That should fix the #1246
+
+2004-09-02 pigi ( pigi@frumar.it)
+ * Version update to 0.99.130
+ * Added patch from pb_ for bug #1251. A lot of thanks to Phil
+
+2004-09-02 pigi ( pigi@frumar.it)
+ * Some changes on output messages to be a little bit clear
+
+2004-09-01 pigi ( pigi@frumar.it)
+ * Applied patches from pb_ (bug #1244)
+ * Added EXTRADIST = ipkg.c and others in Makefile.am as in ipkg.0.99.xxx.tar.gz the ipkg.c was missing. (
+ reported by odvard12@yahoo.com )
+ * Version update to 0.99.129
+
+2004-08-19 Florian <florian.boor@kernelconcepts.de>
+ * Version update to 0.99.128
+ * libipkg.c, ipkg_cmd.c: Fixed return value zero if installation
+ failed. Changed text because failing to install a package
+ is not necessarily a bug :-)
+ * Makefile.in, libbb/Makefile.in: Removed autogenerated files.
+
+2004-08-18 Florian <florian.boor@kernelconcepts.de>
+ * Two more fixed memory leaks. Contributed by Nils Faerber.
+
+2004-08-17 Florian <florian.boor@kernelconcepts.de>
+ * Fix to avoid major memory leak due to multiple initialising
+ of hash tables. Contributed by Nils Faerber.
+
+2004-07-20 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.127
+ * Applied patch from tmbinc@elitedvb.net (Felix Domke) to fix some problems when in use on platforms
+ * different from arm. Fixes big #1234
+2004-06-15 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.126
+2004-06-12 florian <florian.boor@kernelconcepts.de>
+ * Makefile.am: Added some missing headers to the list.
+ * libipkg.pc.in: Fixed hardcoded prefix... tsts
+2004-06-12 pigi ( pigi@frumar.it)
+ * pb_ patch for setuid bit in unarchive
+2004-06-05 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.125
+ * modified almost all reference to xregexec in fnmatch ( as adviced by zap).
+ This should fix every problem with strange character in package name when using regex in functions
+ ( as per info_status_cmd or remove ). #1220
+2004-05-21 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.124
+ * import the kergoth patch for Makefile.am to fix the linking problems on arch <> arm
+ * added the ipkg remove <regexp> feature.
+ * fixed the ipkg usage message, 'cause in "ifdef LIBIPKG" we don't have the ipkg info field version.
+ * added the message "No package removed" if no package has been removed. This to avoid misunderstanding
+ with the successfully done message at the exit of execution.
+2004-05-16 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.122-3
+ * Anothere little fix. Added the version number in control.in. This should fix definitelly the problem with dependencies
+2004-05-16 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.122-2
+ * New subrelease released to correct the problem for dependencies (libipkg >= 0.99.122-1) in ipkg control file
+2004-05-14 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.122-1
+ * needed for a recompilation with the libtool updated. This could fix the #1209 created by my old libtool version
+ * cleaned the cvs dir by removing the really unneeded busybox directory
+2004-05-10 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.122
+ * pb_, cworth and I discussed a bit on ipkg output to users. We agreed on removing some confusing
+ * messages, moving them to a debug level of verbosity.
+ * I do added also some message to user indicating the phase ipkg is in, and a global ending message
+ * informing the user for the status of operation.
+ * This fixes the #1206, and hopefully does not introduce others ;-)
+2004-05-03 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.121
+ * reenoo__ found a problem with depend lines > 1023, and pb fixed it. Thanks to both,
+ * This should fix #1204.
+2004-04-08 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.120
+ * pb found another one. The configure cmd now will set the correct values in status file
+ * #1196 fixed
+2004-04-07 pigi ( pigi@frumar.it)
+ * configure.ac: updated to 0.99.119
+ * pb found another one. Commiting his patch, elegant as usual :)
+2004-03-29 jamey ( jamey@handhelds.org)
+ * configure.ac: updated to 0.99.118
+2004-03-29 pigi ( pigi@frumar.it)
+ * pb_ asked me to have a command to change the status of a package betwenn installed and unpacked.
+ and I did it.
+ * I' ve also included the fix for the empty lists as for bug # 1136 reported and suggested by k.vangelder@chello.nl
+2004-03-17 pigi ( pigi@frumar.it)
+ * Added the implement for Essential in status file. This is needed to avoid the unintentional remove
+ of essential packages. In effect the command "ipkg remove ipkg" worked without problems, but then
+ it was difficult to reinstall. This fix the bug # 867
+2004-03-15 jamey <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.117
+2004-03-10 pigi ( pigi@frumar.it)
+ * Added the check for *alloc in every source. I needed to modify some function ehre and there
+ to check the return values from function allocating memory, but hopefully it should be all right now.
+ * Added the check for at least a package for remove ( it was removing everithing if no pkgname followed the
+ remove option.
+2004-03-09 pigi ( pigi@frumar.it)
+ * Added a flag to disble the checking of directories when the command does not need to
+ read anything from there. Fix bug #1096
+2004-03-09 pigi ( pigi@frumar.it)
+ * Changes to correct the behaviour of verbosity. Now the "0" works, and the "1" is again
+ the default.
+ This fixes the bug #1099
+2004-03-07 pigi ( pigi@frumar.it)
+ * Minimal changes for a clean compile in libipkg.c ( so we can close the bug# 1119 )
+2004-03-03 pigi ( pigi@frumar.it)
+ * Missing \n in Size and Source Fields.
+2004-03-03 pigi ( pigi@frumar.it)
+ * Florian noticed a free missiing in ipkg_cmd.c ( should sleep more at night )
+ it was in an (almost) unsed part of the code ( old code ) but, just in case...
+ * Changed a comment in pkg.c ( it was in italian ) and added a bit of explain in
+ pkg_formatted_field
+2004-03-02 jamey <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.116
+ * pkg.h: from Pigi: pkg_formatted_info and pkg_formatted_field now allocate the strings they fill in
+ * pkg.c, ipkg_cmd.c: from Pigi: updated to the new pkg.h interface
+2004-02-29 florian <florian.boor@kernelconcepts.de>
+ pkg.c: Pigi and me poked around a little bit and located the cause of
+ latest segfault. strncat is not used correctly in pkg_formatted_info
+ and pkg_formatted_field. I added a fix to the only section that
+ triggered the bug and increased a buffer size.
+ BUT: There are many similar bugs remaining!
+2004-02-24 jamey <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.115
+ * ipkg_cmd.c: segv caught by pigi: buffer freed in loop but used on next iterations. bug squashed.
+ * user.c: realloc question buffer if it is too short so that messages are not truncated.
+2004-02-20 jamey <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.114
+ * libbb/unarchive.c: patch from pigi@frumar.it: fix erroneous invalid header checksum message
+2004-02-19 jamey <jamey.hicks@hp.com>
+ * configure.ac: update to 0.99.113
+ * libipkg.c: patch from drw to fix ipkg list
+2004-02-19 florian <florian.boor@kernelconcepts.de>
+ * Some minor changes to make code compile on more compilers.
+2004-02-14 jamey <jamey.hicks@hp.com>
+ * configure.ac: updated to 0.99.112
+ * libbb/unarchive.c: copied in oldgnu tar compatibility mode from latest busybox.
+2004-02-13 jamey <jamey.hicks@hp.com>
+ * configure.ac: updated to 0.99.111
+ * pkg.c: wim delvaux's patch for status file in other destinations
+2004-01-23 florian <florian.boor@kernelconcepts.de>
+ * Applied Dan's patch that adds a package download command to
+ libipkg.
+2004-01-20 florian <florian.boor@kernelconcepts.de>
+ * Applied Dan's changes to work incuded from a C++ app.
+2004-01-15 jamey
+ * configure.ac: updated to 0.99.110
+ * libipkg.c: added default callbacks for output
+ * ipkg_conf.c: default verbosity to 1
+2004-01-12 jamey
+ * configure.ac: updated to 0.99.109
+ * ipkg_install.c: fix potential segv sprintf_alloc with fewer args than required by format string (yay valgrind)
+ * sprintf_alloc.c: add null pointer checking
+2004-01-12 jamey
+ * configure.ac: updated to 0.99.108
+ * Makefile.am, familiar/: use ipkg-cl as default executable, install as ipkg via update-alternatives
+2004-01-12 jamey
+ * configure.ac: updated to 0.99.107
+ * void_list.c: check for null data
+ * pkg.c: check for null pointers
+2003-12-23 florian <florian.boor@kernelconcepts.de>
+ * Added void* parameter to some callbacks.
+
+2003-12-02 florian <florian.boor@kernelconcepts.de>
+ * Added familiar/ipkg-cl.control.in, which is a prototype of
+ control file for ipkg-cl package creation.
+2003-12-01 florian <florian.boor@kernelconcepts.de>
+ * added ipkg command line tool using libipkg, binary is known as ipkg-cl
+ * ipkg-frontend.c: source for this tool
+ * libbb/Makefile.am: Removed changing of CFLAGS, this avoids a nasty warning.
+ * Makefile.am: Same fix and addition of new target creating ipkg-cl.
+ * removed ltmain.sh, libtool which seem to be created by autostuff
+
+2003-12-01 jamey
+ * configure.ac: updated to 0.99.106
+ * pkg.c, ipkg_conf.c: check for null pointers (null pkg->dest in particular)
+2003-11-11 jamey
+ * configure.ac: updated to 0.99.105
+ * ipkg_conf.c: added verbosity option to conf file
+2003-11-11 jamey
+ * configure.ac: updated to 0.99.104
+ * ipkg_install.c: removed spurious calls to fflush, remove obsolete maintainer scripts on upgrade
+ * ipkg_remove.c: remove unused function: remove_conffiles
+2003-11-11 jamey
+ * configure.ac: updated to 0.99.103
+ * libipkg.pc.in, configure.ac: pkgconfig for libipkg
+ * ipkg_conf.c, pkg.c: check for error on fopen
+ * pkg_hash.c: reduced verbosity
+ * libtool: arm-linux-strip does not support --strip-debug on .a files
+2003-11-10 jamey
+ * configure.ac: updated to 0.99.102
+ * ipkg_cmd.c: compute architecture_priority of packages in database before doing download command
+ * conffile.c file_util.[ch] ipkg_install.c: better separation of installation root filenames and actual filenames
+ * pkg.h: added prototype for pkg_free_installed_files
+2003-11-10 jamey
+ * configure.ac: updated to 0.99.101
+ * libipkg changes
+ * generate .list files from file_hash
+2003-11-05 jamey
+ * configure.ac: updated to 0.99.100
+ * ipkg_install.c: fix segv: was passing conflictee->parent instead of conflictee
+2003-10-08 jamey
+ * configure.ac: updated to 0.99.99
+ * ipkg_install.c: use the root_dir after stripping off offline_root prefix
+2003-10-08 jamey
+ * configure.ac: updated to 0.99.98
+ * pkg_hash.c: fixed segv if replaced_by->len was 0
+ * ipkg_cmd.c: ipkg remove with no arguments will remove non-user leaf packages
+ * ipkg_remove.[ch]: export pkg_has_installed_dependents
+ * pkg_depends.c: add pkg->parent to pkg->provides
+ * ipkg_install.c: strip offline_root prefix off of conffile name so comparing the md5sums should work
+ * pkg.c: missing comma added
+2003-10-01 jamey
+ * configure.ac: updated to 0.99.97
+ * ipkg_cmd.c: added whatdependsrec command to show what recursively depends on a package or packages
+ * pkg_vec.[ch]: added pkg_vec_clear_marks and pkg_vec_mark_if_matches
+ * args.c: usage string updated
+2003-09-28 jamey
+ * configure.ac: updated to 0.99.96
+ * ipkg_conf.c: adjusted verbosity
+ * ipkg_install.c: only remove replacee if it is also conflicted, per debian standard
+ * pkg_depends.c: only add to replaced_by if it also conflicts, per debian standard
+ added pkg_provides, pkg_replaces, pkg_conflicts
+ * pkg_hash.c: adjusted verbosity
+2003-09-28 jamey
+ * configure.ac: updated to 0.99.95
+ * args.[ch], ipkg_cmd.c, ipkg_conf.[ch], ipkg_download.c, ipkg_install.c, ipkg_remove.c, pkg.[ch]:
+ Implemented -test mode for ipkg.
+2003-09-28 jamey
+ * configure.ac: updated to 0.99.94
+ * pkg_hash.c: fix pkg_hash_fetch_best_installation_candidate so
+ that one can install another provider of an installed package name
+2003-09-26 jamey
+ * configure.ac: updated to 0.99.93
+ * ipkg_install.c: corrected message level depending on conf->force_depend
+ * ipkg_conf.c: check for duplicate src entries
+ * nv_pair_list.[ch]: added nv_pair_list_find
+2003-09-16 jamey
+ * configure.ac: updated to 0.99.92
+ * pkg_depends.c: some paranoia to try to avoid segv
+ * void_list.c: silenced message about elt not being found
+2003-09-11 jamey
+ * configure.ac: updated to 0.99.91
+ * pkg_depends.c: added pkg_depend_str to fetch right kind of dependence string based on dependence index
+ Use this in add_unresolved_dep.
+ * pkg_depends.h: declaration of pkg_depend_str
+2003-08-22 11:02 jamey
+ * configure.ac: updated to 0.99.90
+ * str_list.[ch]: added str_list_alloc(), added str_list_remove_elt()
+ * void_list.[ch]: added void_list_remove_elt()
+ * pkg_parse.c: added parsing of Source field
+ * pkg_hash.c: updated old_pkg->installed_files list when setting file owner if it was previously owned by old_pkg
+ * pkg_extract.c: use installed_file list if it exists in pkg_extract_data_file_names_to_file
+ * pkg.[ch]: added pkg_write_filelist() and pkg_write_changed_filelists()
+ * ipkg_remove.c: do not call ipkg_conf_write_status_files from ipkg_remove
+ * ipkg_install.c: use ipkg_write_filelist()
+ * ipgk_cmd.c: after writing status file, write any changed pkg filelists
+2003-08-20 11:02 jamey
+ * configure.ac: updated to 0.99.89
+ * pkg.c: print Source field in pkg_print_info
+2003-08-06 18:34 jamey
+ * configure.ac: updated to 0.99.88
+ * pkg_hash: bug 942, declare internal induction variable
+ * ipkg_cmd.c, ipkg_conf.[ch], pkg_src.[ch], pkg_src_list.[ch]: bug 604, support Packages.gz
+2003-08-06 18:34 jamey
+ * configure.ac: updated to 0.99.87
+ * pkg.c: remove extra printing of Suggests field
+ * pkg_vec.c: merge Status field only from current database, rest of Package info from Packages files
+ * pkg_depends.c: print info about recommendations as Notice instead of DEBUG
+2003-07-11 18:34 jamey
+ * configure.ac: updated to 0.99.86
+ * ipkg.h, ipkg_cmd.c, ipkg_configure.c, ipkg_install.c, ipkg_remove.c: only write status file if something changed.
+2003-07-11 18:34 jamey
+ * configure.ac: updated to 0.99.85
+ * pkg.c, pkg.h, pkg_depends.c, pkg_depends.h, pkg_parse.c: bug 885:
+ add recommends and suggests
+ * args.c, ipkg_cmd.c, ipkg_cmd.h: add ipkg configure command
+ * pkg_vec.c: apply patch for bug 883
+2003-05-11 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.84
+ * pkg.c, ipkg-compare-versions.c: fix problem where . and - were not treated as separators in version comparison
+2003-04-11 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.83
+ * ipkg_install.c: use pkg->installed_size instead of pkg->size
+ * ipkg_cmd.c, ipkg_conf.c: put lists under offline_root if specified
+2003-04-11 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.82
+ * pkg_hash.c: ignore Replaces directive when a package replaces itself
+2003-04-10 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.81
+ * pkg.c: clear state_want and state_flags for any uninstallable package
+2003-04-10 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.80
+ * pkg.c: pkg_merge was intermingling depends and predepends from
+ old and new pkg, and was ignoring conflicts and replaces
+ * pkg_depends.c: cleaned up interface to parseDepends
+2003-04-07 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.79
+ * pkg_hash.c: default architecture to host_cpu if unspecified
+ * ipkg_install.c, ipkg_download.c: refuse to install package with no architecture
+2003-04-07 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.78
+ * args.[ch], ipkg_conf.[ch]: added query_all (-A)
+ * ipkg_cmd.c: finished implementing whatdepends, whatrequires, whatprovides, and whatconflicts
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.77
+ * ipkg_cmd.c: implemented whatdepends
+ * ipkg_conf.c: fixed typo
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.76
+ * args.c: was zeroing args structure too late
+ * ipkg_conf.c: test for existence of /etc/ipkg.conf before trying to load it
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.75
+ * familiar/rules: update postinst only to generate ipaqarch.conf if none exists
+ * args.[ch]: added -t or --tmp-dir option to specify tmp-dir
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.74
+ * ipkg_cmd.c: avoid segv by only calling xregfree after xregcomp was called
+ * pkg_hash.c: prefer pkgs that are marked hold/prefer, next
+ abstract pkgs that are installed, next latest pkg if one provider,
+ give up if multiple providers are acceptable -- let user decide
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.73
+ * pkg_hash.c: remove latest_installed heuristic because it prevents upgrades.
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.72
+ * pkg_hash.c: check for unresolved packages (apkg->provided_by->len == 0), better messages.
+2003-04-03 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.71
+ * pkg.c: Added pkg_name_version_and_architecture_compare and abstract_pkg_name_compare
+ * ipkg_cmd.c: allow multiple fields for info and status command.
+ Allow posix regexp's for package name in status, info, and list
+ commands.
+ * pkg_remove.c: fixed type error
+ * xregex.h: added xregfree
+ * pkg_hash.c: Provides functionality seems to be working again
+2003-04-02 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.70
+ * args.c, args.h, ipkg_conf.c, ipkg_conf.h, ipkg_install.c: implemented nodeps option
+ * pkg_vec.[ch]: added [abstract_]pkg_vec_{contains,sort}
+ * pkg.c: print which script not being run in offline root mode
+2003-04-02 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.69
+ * pkg_vec.c: compare architecture to architecture, not to name
+ * ipkg_utils.c: do not exit, instead return NULL
+ * ipkg_install.c: do not exit, instead return -EINVAL
+ * ipkg_download.c: make sure to set pkg dest
+ * ipkg_cmd.c: notice instead of info for writing status file message
+2003-04-02 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.68
+ * pkg_vec.c, pkg_depends.c: pkg_t's are the same if they have same name, version, and architecture
+2003-04-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.67
+ * ipkg_install.c: one last check for supported architecture in ipkg_install_pkg
+ * pkg.c: make pkg_print_field less fragile by using strcasecmp,
+ added support to print Conflicts
+ * pkg_hash.c: if multiple candidates with right architecture
+ satisfy constraint_fcn, return latest version
+ * ipkg_cmd.c: when verbosity > 1, show if conffiles have been
+ modified in info command
+ * hash_table.c, hash_table.h: count number of elements in hash
+ tables
+ * file_util.c: explicitly use unsigned char
+ * conffile.c: more debugging info
+2003-04-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.66
+ * pkg_depends.c: fixed what seemed to be glaring deficiency in version_constraints_satisfied
+ * pkg_hash.c: more debug info
+ * pkg_parse.c, pkg.c: added Installed-Time as field saved to status file
+2003-04-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.65
+ * ipkg_cmd.c, ipkg_conf.c: applied ipkg dest installation patch from Ben Lau <benlau@linux.org.hk>
+ * ipkg_cmd.c: fixed probably segv when using offline_root, fixed problem installing from local file.
+ * ipkg_conf.c:
+ - Do not add default architectures if ipkg configuration files include architecture definitions.
+ - Look for /etc/ipkg/*.conf under offline root if using offline root mode
+ * void_list.h: added void_list_empty()
+ * nv_pair_list.h: added nv_pair_list_empty()
+2003-03-28 14:30 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: 0.99.64
+ * pkg_hash.c: change fprintf stderr to ipkg_message
+ * pkg.h: added SF_MARKED and abstract_pkg_t state_flag field
+ * pkg.c: include Provides, Replaces, and Architecture in status
+ file
+ * ipkg_remove.c: make sure to print each dependent package only
+ once
+ * ipkg_message.h: added IPKG_DEBUG2
+ * ipkg_install.c: modify message and level depending on
+ force_depends
+ * ipkg_cmd.c: call pkg_info_preinstall_check before any
+ install/upgrade/remove action
+ * ChangeLog, autoconfigure.sh, includes.h,
+ ipkg_conf.c, ipkg_remove.c, pkg.c, pkg.h, update-alternatives,
+ xregex.h: applied kergoth's update-alternatives patch
+ * ipkg_cmd.c, ipkg_remove.c: remove maybe_broken_removal... which
+ was an expensive no-op; before removing package, make sure that
+ nothing is installed that depends on the apkgs **provided** by a
+ package
+ * pkg.h: mark for future cleanup
+ * ChangeLog: 0.99.62, adds architecture priority, better handling
+ of file obsolescence and package replacements in progress
+2003-03-27 18:26 jamey
+ * autoconfigure.sh: accidentally committed /usr/local/bin calls
+ * ipkg_conf.c: needed a strdup, set default verbosity back to 0
+ * familiar/postinst: default architecture priorities
+ * Makefile.in, autoconfigure.sh, ipkg_cmd.c, ipkg_conf.c, pkg.c:
+ both name and value in nv_pair_list must be actual strings
+ * pkg_hash.c: do not try to invoke NULL constraint_fcn
+ * ipkg_install.c: added file_hash_{set,get}_file_owner, created
+ check_downgrade
+ * ipkg_conf.c, ipkg_conf.h, ipkg_remove.c, pkg.c, pkg_hash.c,
+ pkg_hash.h: added file_hash_{set,get}_file_owner
+ * hash_table.c: check for key already being present in
+ hash_table_insert
+ * configure.ac: update to 0.99.63
+ * ipkg_hash_test.c: update due to new prototypes
+ * ipkg_conf.c: missed a conversion from str_list to nv_pair_list
+ * ipkg_install.c: minor tweaks
+ * pkg.c, pkg.h: added pkg_info_preinstall_check to update
+ pkg->arch_priority
+ * pkg_depends.c, pkg_depends.h: use constrained
+ pkg_hash_fetch_best_installation_candidate in
+ pkg_hash_fetch_unsatisfied_dependencies
+ * pkg_hash.c, pkg_hash.h, ipkg_cmd.c, ipkg_upgrade.c: split
+ pkg_hash_fetch_best_installation_candidate into a by name and a
+ constrained version
+ * ipkg_install.c: block SIGINT while doing core of package
+ installation (single package)
+ * ipkg_conf.c, ipkg_conf.h: support for architecture priority
+ * pkg_depends.c: cleanup, reindent
+ * pkg.c, pkg.h: support for architecture_priority
+ * ipkg_cmd.c: installed SIGINT handler when upgrading or removing,
+ support for architecture_priority
+ * pkg_hash.c: added support for architecture priority, reindented
+ * pkg_vec.c: minor cleanup
+2003-03-24 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.61
+ * familiar/postinst: mkdir -p /etc/ipkg
+2003-03-24 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.61
+ * ipkg_conf.c: read configuration from all *.conf files in /etc/ipkg/
+ * familiar/postinst: create /etc/ipkg/*.conf according to platform ipkg is installed on
+2003-03-20 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.60
+ * various: added support for package architectures
+ * configure.ac: do not test for malloc
+2003-03-17 Aman Gupta <ipkg@themastermind1.net>
+ * configure.ac: updated to 0.99.59
+ * args.c: show all verbosity levels in usage info
+ * args.h: changed default verbosity level to 1
+ * ipkg_cmd.c: ipkg_multiple_files_scan() was useless, switch to using
+ ipkg_prepare_url_for_install()
+ * ipkg_install.c: fix --force-reinstall
+ * ipkg_remove.c: stop removing of modified conffiles
+2003-03-04 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.56
+ * ipkg_message.c: show error messages by default
+ * ipkg_message.h: protect against multiple inclusion
+ * conffile.[ch]: switch to ipkg_message, added conf argument to conffile_has_been_modified
+ * ipkg.h: move EXTENSION macros here
+ * pkg_depends.c: minor cleanup
+ * pkg.h: added prefer and obsolete flags
+ * pkg.c: parse and unparse SF_PREFER and SF_OBSOLETE
+ * ipkg_install.[ch]:
+ - added {pkg,name}_mark_dependencies_for_installation,
+ - added conf argument to conffile_has_been_modified
+ - missing ifdef IPKG_DEBUG_NO_TMP_CLEANUP
+ * ipkg_remove.c: added conf argument to conffile_has_been_modified
+ * ipkg_download.c: added ipkg_prepare_for_install
+2003-03-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.55
+ * ipkg.h: wrap #if 0 around definition of of IPKG_DEBUG_NO_TMP_CLEANUP
+2003-03-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.54
+ * ipkg_install.c: make old package SW_DEINSTALL during ipkg installation
+ * ipkg_cmd.[ch]: added some code to install packages marked SW_INSTALL, but have not enabled this code yet.
+2003-03-01 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: updated to 0.99.53
+ * pkg_depends.c: let SW_INSTALL satisfy dependences (instead of SS_INSTALL)
+2003-03-01 Daniele Nicolodi <daniele@grinta.net>
+ * ipkg_install.c: indentation fixes and finish switch to message
+ facility
+ * ipkg_cmd.c: indentation fixes, switch to message facility and
+ some code cleanup
+ * ipkg_message.c (ipkg_message): check for a NULL *conf parameter
+ * ipkg_message.h: renamed IPKG_ERR in IPKG_ERROR
+2003-02-28 Jamey Hicks <jamey@handhelds.org> (patch from Daniele Nicolodi <daniele@grinta.net>)
+ * configure.ac: incremented version to 0.99.5
+ * ipkg_message.[ch]: added message facility
+ * args.[ch]: verbosity control
+ * ipkg_conf.[ch]: verbosity control
+ * ipkg_install.c: switch to using message factility
+2003-02-28 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version to 0.99.51
+ * ipkg_cmd.c: added ipkg_statisfy_all_dependences, called after
+ install/upgrade of packages to handle packages that were split and
+ no longer provide all the resources they used to provide.
+2003-02-27 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version to 0.99.50
+ * ipkg_cmd.c: write out status after doing an upgrade
+2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb)
+ * configure.ac: incremented version to 0.99.49
+ * pkg_parse.c, pkg.c: do not treat deb revision specially
+2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb)
+ * configure.ac: incremented version number to 0.99.48
+ * args.c: added help for ipkg flags sub-command
+ * ipkg_cmd.c: added ipkg_flag_cmd, do not upgrade package marked hold
+ * ipkg_install.c: do not remove obsolesced files if old_pkg is flagged noprune
+ * ipkg_remove.c: pkg->state_flag is a bitvector now
+ * pkg.c: pkg->state_flag is a bitvector now
+ * pkg.h: pkg->state_flag is a bitvector now
+2003-02-27 Jamey Hicks <jamey@handhelds.org> (another patch from pb)
+ * configure.ac: incremented version number to 0.99.47
+ * pkg.c: refix "uninstalled package has NULL tmp_unpack_dir"
+ * pkg_hash.c:
+2003-02-27 Aman Gupta <oz@themastermind1.net> (another patch from pb_)
+ * configure.ac: incremented version number to 0.99.46
+ * pkg.c: fix "uninstalled package has NULL tmp_unpack_dir"
+2003-02-24 Jamey Hicks <jamey@handhelds.org> (per patch from Philip Blundell <pb@handhelds.org>)
+ * configure.ac: incremented version to 0.99.45
+ * file_util.c: include space for null in line_size
+ * ipkg_cmd.c: sigint handler while configuring packages
+ * ipkg_install.c: state_status != SS_INSTALLED and != SS_UNPACKED
+ * ipkg_remove.c: missing i++
+ * pkg.c: do not run scripts in offline_root mode
+ * pkg_depends.c: every package provides itself
+ * pkg_hash.c: better handling of packges provided by multiple providers
+2003-02-24 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version number to 0.99.44
+ * args.c: added doc for -force-overwrite
+2002-11-26 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version number to 0.99.43
+ * ipkg_install.c: completely skip the space check when -force_space asserted
+2002-11-23 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version number to 0.99.42
+ * args.c: missed one spot checking for -force_space or -force-space
+2002-11-23 Jamey Hicks <jamey@handhelds.org>
+ * configure.ac: incremented version number to 0.99.41
+ * ipkg_install.c: added -force_space option to override out of space check
+2002-11-23 Aman Gupta <oz@themastermind1.net>
+ * configure.ac: incremented version number to 0.99.40
+ * ipkg_configure.c: updated to match new text output format
+ * ipkg_install.c: updated to new text output format
+ fixed problems where ipks installed from file or
+ http were being installed over newer ipks of the
+ same name
+ * ipkg_remove.c: updated to new text output format
+ made ipkg remove do what ipkg purge originally did,
+ by having it remove conffiles, and status entries for
+ ipks that are removed. ipkg_purge now calls
+ ipkg_remove
+2002-11-22 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.39
+ * applied patches from Aman Gupta for better handling of dests
+2002-11-?? Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.38
+2002-11-07 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.37
+ * hash_table.[ch]: moved internals of hash_tables out of pkg_hash.c
+ * pkg_hash.c: moved internals of hash_tables out of pkg_hash.c
+2002-10-29 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.37
+ * ipkg_cmd.c: ipkg_upgrade_cmd now installs uninstalled packages
+ instead of getting a segv
+2002-10-29 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.36
+ * changed verbose_get to verbose_wget as documented
+2002-08-08 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.34
+ * ipkg_cmd.c: fixed problem stringifying HOST_CPU
+ * Makefile.am: helped fix problem stringifying HOST_CPU
+2002-08-08 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.33
+ * ipkg_cmd.c, args.c: added print-architecture and print-installation-architecture commands
+ * Makefile.am: added defines for HOST_CPU and BUILD_CPU to CFLAGS and package: target
+2002-08-08 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.32
+ * pkg.c: removed chroot breakage
+2002-08-07 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.31
+ * other: applied multiple providers patch from philip blundell
+ * ipkg_cmd.c: implemented compare_versions cmd
+2002-07-25 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.30
+ * ipkg_conf.c: added offline_root_pre_script_cmd and offline_root_post_script_cmd
+ * pkg.c: execute scripts in chroot'ed environment running
+ pre_script_cmd and post_script_cmd before and after the pkg script.
+2002-07-24 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.29
+ * pkg.c: fixed a segv when printing Replaces field
+2002-07-24 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.28
+ * ipkg_cmd.c: merged functionality from ipkg_install_cmd into
+ ipkg_upgrade_cmd with an eye towards unifying these two commands.
+ * ipkg_install.c: installing a package that replaces other
+ packages removes them first. (Upgrade does not do replacements automatically).
+ * ipkg_remove.c: ipkg_remove_pkg will remove a package with
+ installed dependents if state_flag == SF_REPLACE.
+2002-07-24 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.27
+2002-07-23 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.26
+ * renamed pkg_vec_init/pkg_vec_deinit to pkg_vec_alloc/pkg_vec_free
+ * started implementation of Replaces
+2002-07-22 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.25
+ * many cleanups trying to regain stability
+2002-07-22 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.24
+ * various files: trying to stomp a segv in conflicts checking.
+2002-07-17 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.23
+ * ipkg_remove.c: do not do recursive removal if force-depends is
+ specified
+ * other-files: other cleanups to reduce code clutter
+2002-07-16 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.22
+ * user.[ch]: moved user interaction procedure here
+ * args.[ch], ipkg_conf.[ch]: added force_removal_of_dependent_packages
+ * pkg.h: added state_status to abstract_pkg_t
+ * ipkg_remove.c: If package has installed dependents, then only
+ remove if force_removal_of_dependent_packages is asserted in
+ ipkg.conf or on command line. Will add user interaction option later.
+2002-07-16 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.21 after
+ applying dependent removal and conflicts patch.
+
+2002-07-14 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.20
+ * ipkg_download.c: removed useless -N flag from wget
+ * update-alternatives: 'head -1' -> 'head -n 1', no sort -k 2 for busybox
+
+2002-07-15 Karthikeyan K <karthik@innvo.com>
+
+ * ipkg_remove.c (ipkg_remove_dependant_pkgs): removed setting the
+ dependencies_checked variable in the while loop b4 actually checking
+ the dependencies of that package.
+ * ipkg_cmd.c (ipkg_multiple_files_scan): added check for ".ipk" and
+ ".deb" extension, so that no caching is attempted on arguments that
+ are not local files
+ * pkg_depends.c (pkg_hash_fetch_conflicts): while returning NULL,
+ casted to (pkg_vec_t *) to compile without warnings
+
+2002-07-12 Abhaya Shenoy <abhaya@innvo.com>
+
+ * pkg_depends.c (pkg_hash_fetch_conflicts): use new abstract_pkg_vec
+ structure in checking provided_by
+
+2002-07-07 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.18
+ * fixed a segv due to type error in provides support
+
+2002-07-07 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.17
+ * updated provides support so that installed provider is preferred to
+ uninstalled provider
+
+2002-07-05 Abhaya Shenoy <abhaya@innvo.com>
+
+ * pkg_depends.c (pkg_hash_fetch_conflicts): check for conflicts
+ found before returning
+
+2002-07-04 Abhaya Shenoy <abhaya@innvo.com>
+ * ipkg_install.c (check_conflicts_for): new function to call
+ pkg_hash_fetch_conflicts and print offending packages
+ (ipkg_install_pkg): added call to check_conflicts_for
+ * pkg.c (pkg_merge): provides from oldpkg should be given
+ priority
+ (pkg_init): init of conflicts, conflicts_count fields
+ * pkg.h (struct pkg): added fields conflicts_str, conflicts,
+ conflicts_count
+ * pkg_depends.c (pkg_hash_fetch_conflicts): new function to check
+ for conflicts
+ (buildConflicts): new function to set up the conflicts in the pkg
+ struct
+ * pkg_depends.h: added new type CONFLICTS to depend_type enum
+ * pkg_hash.c (hash_insert_pkg): added call to buildConflicts
+ * pkg_parse.c (pkg_parse_raw): added parsing of Conflicts
+
+2002-07-04 Karthikeyan K <karthik@innvo.com>
+
+ * ipkg_cmd.c (ipkg_multiple_files_scan): new function to handle installation
+ of already downloaded files
+ (ipkg_install_cmd): added call to ipkg_multiple_files_scan
+ (ipkg_remove_cmd): added call to possible_broken_removal_of_packages
+ * ipkg_install.c (ipkg_install_pkg): added check to remove redundant upgrade
+ when a package to be installed is already installed as a dependancy of
+ another
+ * ipkg_remove.c (possible_broken_removal_of_packages): new fnuction
+ to check that all packages can be removed, before actually starting to
+ remove them
+ (ipkg_remove_dependant_pkgs): new function to remove dependant packages
+ (ipkg_remove_pkg): added call to ipkg_remove_dependant_pkgs
+ * pkg.c (abstract_pkg_init): initialized dependencies_checked
+ * pkg_hash.c (pkg_hash_dump): added more information to hash dump
+
+2002-07-03 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.16
+ * ipkg_install.c: defensive programming in case pkg contains no Size: clause
+
+2002-07-02 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.15
+ * pkg_depends.c: check for provided_by when fetching unsatisfied dependencies
+
+2002-07-02 Jamey Hicks <jamey.hicks@hp.com>
+ * configure.ac: incremented version number to 0.99.14
+ * pkg_hash.c: if abstract pkg is provided_by, then return pkg vec
+ of first package that provides it.
+
+2002-06-17 Jamey Hicks <jamey.hicks@hp.com>
+
+ * configure.ac: incremented version number to 0.99.12
+ * args.h, ipkg_conf.h, ipkg_install.c: Added force_overwrite
+ option. When this is asserted, ipkg will overwrite files that
+ have no owner or that belong to other packages.
+ * ipkg_conf.c, ipkg_dest.c: Update status file atomically, keeping
+ old copy of status file if cannot update new status file. Applied
+ patch from Jukka Santala for this fix.
+
+2002-03-16 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version number to 0.99.9-1.
+
+ * RELEASE_NOTES: Added release notes for 0.99.9-1.
+
+2002-03-15 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version number to 0.99.9.
+
+ * RELEASE_NOTES: Added release notes for 0.99.9.
+
+ * Makefile.am (bin_PROGRAMS): Install update-alternatives as well.
+
+ * familiar/rules (binary-arch): Mv all of /bin to /usr/bin
+
+ * configure.ac: Incremented version number to 0.99.8.
+
+ * RELEASE_NOTES: Added release notes for 0.99.8.
+
+ * familiar/rules (binary-arch): Fixed to use "make install-strip"
+ rather than "make install" and a strip command.
+
+ * ipkg_cmd.c (ipkg_install_cmd): Moved an error message up from
+ ipkg_install_by_name, (eventually all error messages should come
+ up out of what will become libipkg, (pkg.c, ipkg_install.c, etc.)
+ and into ipkg_cmd.c and friends).
+ (ipkg_upgrade_pkg): Pushed downgrade check down into
+ ipkg_install_by_name so that "ipkg install foo" will do the
+ downgrade check.
+
+ * ipkg.h: Rename some ipkg_error_t error codes to be more
+ consistent.
+
+ * ipkg_install.c (resolve_conffiles): Added missing removal of
+ backed-up modified conffiles, (which led to bizarre, bogus
+ conffile prompting the next time the package was upgraded).
+ (user_prefers_old_conffile): Fixed reversed arguments to diff in
+ interactive conffiles prompting.
+ (ipkg_install_by_name): Fixed "ipkg install foo" to never
+ downgrade foo, (just like "ipkg upgrade foo").
+
+ * familiar/rules: Added installation of
+ /usr/share/doc/ipkg/copyright file. Fixed so that ipkg.conf goes
+ to /etc, not /usr/etc, (but still keep binary in /usr/bin not
+ /bin). Changed name of installed binary from ipkg-unstable to
+ ipkg.
+
+ * familiar/control.in (Package): Changed package name from
+ ipkg-unstable to ipkg.
+
+ * pkg_parse.c (parseVersion): Fixed to ignore whitespace at
+ beginning of version string.
+ (pkg_parse_raw): Fixed segfault if a package record list ends with
+ a package paragraph without a final blank line.
+
+ * ipkg_install.c (check_data_file_clashes): Improved wording of
+ file clash error message.
+
+ * ipkg_download.c (ipkg_download_pkg): Fixed segfault if package
+ has no src, (occurs if package had benn installed locally, then
+ was removed (but not purged), then tried to reinstall eithout it
+ existing in any /usr/lib/ipkg/lists/* file).
+
+ * etc/ipkg.conf: Added a default ipkg.conf to the distribution.
+
+2002-03-13 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version to 0.99.7.
+
+ * RELEASE_NOTES: Added release notes for 0.99.7.
+
+ * pkg.c (pkg_run_script): Added support to export
+ IPKG_OFFLINE_ROOT. This is really a nasty hack as it means scripts
+ need to be modified to check IPKG_OFFLINE_ROOT. I'd really prefer
+ coming up with a good, reliable chroot system. But for now this
+ will let update-alternatives work, (which already does examine
+ IPKG_OFFLINE_ROOT).
+ (pkg_run_script): Added missing brace.
+
+ * ipkg_conf.c (ipkg_conf_init): Reworked significantly to properly
+ set up the pkg_dest_list stuff to account for offline_root.
+
+ * args.c (args_parse): Added support for -force_defaults in
+ addition to -force-defaults, etc. as I kept mistyping these
+ somehow.
+
+2002-03-12 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version to 0.99.6.
+
+ * RELEASE_NOTES: Added release notes for 0.99.6.
+
+ * ipkg_download.c (ipkg_download): Fixed bug in handling of
+ "file://" URLs.
+
+ * ipkg.c (main): Fixed to abort if ipkg_conf_init fails.
+
+ * ipkg_conf.c (ipkg_conf_init): Fixed to complain if given an
+ unknown dest.
+
+ * pkg.c (pkg_print_field): Fixed several fields to not print if
+ NULL, (Architecture. Maintainer, Size, Filename, Description)
+
+ * args.c (args_parse): Fixed bug that was always setting
+ force_removal_of_essentail_packages (yikes!).
+
+ * configure.ac: Incremented version to 0.99.5.
+
+ * RELEASE_NOTES: Added release notes for 0.99.5.
+
+ * familiar/rules (binary-arch): Added strip back in in preparation
+ of non-unstable release of ipkg.
+
+ * str_util.c (str_starts_with): Added convenience function.
+
+ * pkg_extract.c (pkg_extract_data_file_names_to_file): Fixed
+ filenames in *.list files to be compatible with dpkg and the old
+ ipkg, (no prefix of "." for example).
+
+ * pkg.c (pkg_run_script): Added export of PKG_ROOT for the benefit
+ of maintainer scripts.
+
+ * ipkg_remove.c (ipkg_remove_pkg): Complain and abort if user
+ attempts to remove an essential package, (also inform them of the
+ force option if they insist).
+
+ * ipkg_install.c (ipkg_install_pkg): Added message about whether
+ installing or upgrading.
+
+ * ipkg_download.c (ipkg_download): Added support for "file://"
+ URLs, (untested).
+ (ipkg_download): Added support for wget proxy options.
+
+ * ipkg_conf.c (ipkg_conf_init): Added proxy support to ipkg_conf,
+ (http_proxy, ftp_proxy, no_proxy, proxy_user, and proxy_passwd).
+
+ * ipkg_cmd.c (ipkg_upgrade_pkg): Moved Upgrading message from
+ ipkg_upgrade_cmd to ipkg_install_pkg.
+
+ * args.c (args_parse): Added new option
+ -force-removal-of-essential-packages, (which is intentionally
+ painful to type and not listed in usage. It should not be used
+ often).
+
+2002-03-11 Carl Worth <cworth@east.isi.edu>
+
+ * configure.ac: Incremented version to 0.99.3.
+
+ * RELEASE_NOTES: Added release notes for 0.99.3.
+
+ * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Fixed
+ to avoid infinite loop in the case of a circular dependency.
+
+ * configure.ac: Incremented version to 0.99.2.
+
+ * RELEASE_NOTES: Added release notes for 0.99.2.
+
+ * familiar/rules: Commented out strip, (temporary until this beast
+ is deemed more stable).
+
+ * xsystem.c (xsystem): Cleaned up error message, (missing
+ newline).
+
+ * pkg.c (pkg_merge): Made pkg_merge a NOP if oldpkg == newpkg.
+ (pkg_print_field): Don't print MD5sum field if NULL.
+
+ * ipkg_install.c (satisfy_dependencies_for): Now returns error
+ status if one or more of the dependencies fail to install cleanly.
+ (unpack_pkg_control_files): Fixed to not tack on a bunch of
+ NULL-valued conffiles entries if non-NULL conffiles already
+ exist. This fixed the errant prompting for unmodified conffiles
+ during -force-reinstall.
+ (unpack_pkg_control_files): Cleaned up conffile filenames to not
+ have ugly things like "///" inside them.
+
+ * ipkg_download.c (ipkg_download): Cleaned up error message.
+ (ipkg_download): Now uses new file_move function.
+ (ipkg_download_pkg): Created new function, (from old code in ipkg_install).
+
+ * ipkg_cmd.c (ipkg_download_cmd): Added new "ipkg download"
+ command.
+
+ * file_util.c (file_move): Created file_move, (from code that had
+ been in ipkg_download).
+ (file_copy): Added error message on failure.
+
+ * conffile.c (conffile_has_been_modified): Eliminated crash if
+ conffile_has_been_modified is called with conffile->value == NULL.
+
+2002-03-09 Carl Worth <cworth@east.isi.edu>
+
+ * RELEASE_NOTES: Added release notes for 0.99.1
+
+ * configure.ac: Incremented version to 0.99.1
+
+ * pkg_hash.c (pkg_hash_pkg_owning_file): Fixed to actually return
+ NULL if no package owns a file.
+
+ * pkg.c (pkg_get_installed_files): Added installed_files_ref_cnt
+ to pkg_t to prevent pkg->installed_files from being freed from an
+ inner loop while still being used by an outer loop, (which was
+ happening).
+
+ * pkg_hash.c (pkg_hash_pkg_owning_file): Moved this function in
+ from pkg_dest.c. Also, updated it to use pkg_get_installed rather
+ than mucking around inside /usr/lib/ipkg and globbing for *.list
+ files.
+ (pkg_hash_fetch_best_installation_candidate): Fixed to only return
+ a package that actually could be installed, (ie. it must have
+ either a local_filename or a non-NULL src from which it could be
+ downloaded). This prevents a segfault during "ipkg upgrade".
+
+ * pkg.c (pkg_get_installed_files): Fixed to not do strange things
+ to filenames such as: "//./bin/sh"
+
+ * ipkg_cmd.c (ipkg_files_cmd): Added pkg_free_installed_files to
+ conserve a bit of memory.
+ (ipkg_search_cmd): Updated to use pkg_get_installed rather than
+ mucking around inside /usr/lib/ipkg and globbing for *.list files.
+
+ * pkg.c (pkg_free_installed_files): Added this function to free up
+ memory from pkg_get_installed_files.
+
+ * ipkg_conf.c (ipkg_conf_set_option): Added force_reinstall option
+ to allow reinstallation of an installed package.
+
+ * args.c (args_parse): Added -force-reinstall option to enable
+ reinstallation of an installed package.
+
+ * busybox-0.60.2/ar.c (ar_main): Updated unarchive call to track
+ prototype change.
+
+ * busybox-0.60.2/libbb/unarchive.c (free_header_ar): Added
+ function to plug memory leak.
+
+ * ipkg_install.c (check_data_file_clashes): Fixed crash if no
+ package can be found owning the pre-existing file.
+
+ * pkg_dest.c (pkg_dest_deinit): Fixed bug that pkg_dest was
+ holding on to freed data rather than making a local copy.
+
+ * pkg_depends.c (freeDepends): Fixed crash when pkg->depends is NULL.
+
+ * RELEASE_NOTES: Added release notes for 0.98.0 and 0.99.0.
+
+ * busybox-0.60.2/libbb/unarchive.c (extract_archive): Fixed
+ bug. Always alloc memory for full_name so we don't free data that
+ we shouldn't.
+ (unarchive): Updated to accept a free_headers function pointer as
+ a counterpart to get_headers, to eliminate memory leaks.
+ (free_header_tar): Implemented cleanup function as counterpart to
+ get_header_tar, to eliminate memory leaks.
+ (deb_extract): Added several calls to free_header_tar to eliminate
+ memory leaks.
+
+ * str_util.c (str_dup_safe): Added convenience function. Like
+ strdup, but safe to use on a NULL pointer.
+
+ * pkg_vec.c (pkg_vec_insert): Updated to use new pkg.c:pkg_merge
+ rather than marry_two_packages. With this change the free(pkg) is
+ now here rather than one level deeper. Eventually, I want to get
+ this free(pkg) up and out of pkg_hash_insert.
+
+ * pkg_parse.c (parseDependsString): Fixed bug walking off the end
+ of the raw buffer looking for a character that isspace().
+ (parseConffiles): Fixed big bug parsing Conffiles field where all
+ conffiles appear on the same line.
+
+ * pkg_hash.c (pkg_hash_add_from_file): Plugged memory leak of data
+ allocated deep down in read_raw_pkgs_from_file.
+
+ * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Plugged
+ memory leak, (missing pkg_vec_deinit).
+ (freeDepends): Added this function as the counterpart to
+ buildDepends. Getting closer to chasing down all memory leaks.
+ (depend_deinit): Added this function as the counterpart to
+ depend_init. Getting closer to chasing down all memory leaks.
+ (parseDepends): plugged memory leak of pkg_name.
+
+ * pkg.c (pkg_deinit): Added pkg_deinit to take care of freeing any
+ memory owned by a pkg_t.
+ (pkg_init_from_file): This function was 100% broken, (missing
+ rewind).
+ (pkg_merge): Moved pkg_merge here from
+ pkg_vec.c:marry_two_packages. Started work to make it
+ non-destructive, (not finished).
+ (pkg_print_info): Added Status and Essential fields to
+ pkg_print_info.
+ (pkg_print_status): Fixed pkg_print_status to work whether or not
+ the package is installed.
+
+ * ipkg_utils.c (read_raw_pkgs_from_file): Moved fclose out of
+ read_raw_pkgs_from_stream and into this function where it belongs,
+ (since the fopen occurs here).
+ (trim_alloc): Fixed trim to not free data passed in. Changed the
+ name to make it obvious that it is allocating memory.
+
+ * ipkg_install.c (ipkg_install_from_file): Fixed to be more robust
+ to the fact that hash_insert_pkg sometimes frees the data that I
+ pass into it (!).
+ (satisfy_dependencies_for): Cosmetic change to messages.
+ (satisfy_dependencies_for): Now sets the dest on to-be-installed
+ packages, so that the state_want flag can be written to a status
+ file if necessary.
+ (satisfy_dependencies_for): Added pkg_vec_deinit to plug memory
+ leak.
+ (ipkg_install_pkg): Added "run ipkg update?" hint to error
+ message.
+ (backup_modified_conffiles): Made more robust to the case that a
+ conffile has disappeared.
+ (install_maintainer_scripts): Fixed bug that was installing
+ maintainer scripts as libFoopostinst rather than
+ libFoo.postinst. This was preventing postinst scripts from being
+ executed.
+ (cleanup_temporary_files): Added missing closedir to plug a memory
+ leak.
+
+ * ipkg_download.c (ipkg_download): Cosmetic change to error
+ messages.
+
+ * ipkg_conf.c (ipkg_conf_parse_file): Plugged some small memory
+ leaks.
+ (ipkg_conf_set_option): Changed configuration options from
+ force-depends, force-defaults to force_depdends, force_defaults to
+ be compatible with old ipkg.conf files.
+ (ipkg_conf_set_option): Fixed bug in parsing options.
+ (ipkg_conf_write_status_files): Fixed to list all interesting
+ packages, (any with non-default state), in status file rather than
+ just installed files.
+ (ipkg_conf_write_status_files): Plugged a memory leak.
+
+ * ipkg_cmd.c (ipkg_status_cmd): Changed "ipkg status" to use
+ pkg_print_info so it is much more verbose, (includes fields such
+ as Maintainer, etc. that are merged in from the lists files).
+
+ * ipkg.h (IPKG_DEBUG_NO_TMP_CLEANUP): Added compile-time option to
+ preserve temporary files for easier debugging.
+
+ * file_util.c (file_md5sum_alloc): cosmetic changes to variable
+ names.
+
+ * ipkg_conf.c (ipkg_conf_init): Added support for offline_root
+ configuration file option.
+
+ * args.c (args_init): Added support for -o, -offline,
+ -offline-root command-line arguments. (Although they don't really
+ have any effect yet).
+
+ * ipkg_install.c (ipkg_install_pkg): Changed back to marking
+ package as installed before postinst, (the pkg_run_script wanted
+ to find the scripts in /usr/lib/ipkg/info). Actually, it could
+ probably find the script in either place at this point so maybe it
+ doesn't really matter.
+
+2002-03-07 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_install.c (ipkg_install_pkg): Changed to only mark package
+ as installed after running ipkg_configure, (to run the postinst
+ script).
+
+ * RELEASED ipkg-unstable 0.99.0
+
+ * Updated all instances of "XXX" in the code to indicate one of
+ the following categories:
+ XXX: BUG: This is a bug that needs to be fixed.
+ XXX: QUESTION: Implementation approach is uncertain here.
+ XXX: CLEANUP: Suggestion on how the code could be cleaned up.
+ XXX: FEATURE: Comment describes a useful feature request.
+
+ * pkg.c (pkg_print_status): Added the Depends field to package
+ paragraphs in the status file, ("ipkg remove" will need this).
+
+ * ipkg_install.c (satisfy_dependencies_for): Fixed "ipkg install"
+ to not complain several times about "Package foo already
+ installed" when doing large recursive installs.
+ (ipkg_install_pkg): "ipkg install foo" for an installed package
+ will now check and install any missing dependencies before exiting
+ with "Package foo is alrady installed."
+
+2002-03-06 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_dest.c (pkg_dest_pkg_owning_file_alloc): Moved this function
+ here from ipkg_install.c. Also plugged a memory leak in it with
+ globfree.
+
+ * pkg.c (pkg_remove_installed_files_list): Fixed bug that
+ prevented package.list file from ever being removed during "ipkg
+ remove".
+
+ * ipkg_remove.c (remove_data_files_and_list): Fixed noisy and
+ spurious warnings about non-empty directories. "ipkg remove"
+ should now only say anything if a directory that was solely
+ provided by that package is non-empty.
+
+ * ipkg_cmd.c (ipkg_install_pending_cmd): Plugged memory leak with
+ globfree.
+
+ * ipkg_install.c: *Many* fixes to enable "ipkg upgrade" to more or
+ less work. Primarily fixing file clash identification and conffile
+ handling/resolution. "ipkg upgrade" has now worked correctly on
+ several test cases!
+
+ * ipkg_install.c (unpack_pkg_control_files): Now initializes
+ conffiles list from the contents of conffiles control file,
+ (leaves md5sum calculation until the actual conffiles are
+ extracted later).
+ (ipkg_install_pkg): Separated backup_modified_conffiles and
+ check_data_file_clashes into separate functions.
+ (preinst_configure): Simplified this function pushing its old
+ logic into pkg.c:pkg_run_script.
+ (backup_modified_conffiles): Added backup of any conffiles that
+ are new as of this upgrade.
+ (check_data_file_clashes): First real implementation of
+ check_data_file_clashes.
+ (resolve_conffiles): First real implementation of
+ resolve_conffiles.
+ (backup_make_backup): Added this and a few other functions to
+ abstract backup creation/removal.
+ (find_pkg_owning_file): Added this function.
+
+ * pkg_extract.c (pkg_extract_data_files_to_dir): Fixed args to
+ deb_extract so that existing files will be overwritten, (and any
+ other error messages will no longer be suppressed).
+
+ * pkg.c (pkg_print_status): Added Conffiles field to
+ pkg_print_status.
+ (pkg_print_field): Fixed crash when printing NULL Conffiles
+ values.
+ (pkg_get_conffile): Fixed crash if pkg_get_conffile called with a
+ NULL pkg.
+ (pkg_run_script): Made pkg_run_script smart enough to run scripts
+ for uninstalled packages, (from
+ <pkg_tmp_unpack_dir>/<script_name>), as well as for isntalled
+ packages, (from <dest_info_dir>/<pkg_name>.<script_name>
+
+ * str_util.c (str_tolower): Added convenience function.
+ (str_toupper): Added convenience function.
+
+ * nv_pair.c (nv_pair_init): Fixed crash from calling nv_pair_init
+ with NULL value.
+
+ * pkg.c (pkg_init_from_file): Fixed bug -- forgot to close file.
+
+ * file_util.c (file_md5sum_alloc): Convenience wrapper around
+ md5_stream as ripped out of busybox. This function takes care of
+ file open/close and does the bin2hex conversion of the md5sum.
+
+ * conffile.c (conffile_has_been_modified): Implemented this
+ function for real now that we have md5sum capability.
+
+ * md5.c (md5_stream): Sucked in md5sum calculation code from
+ busybox, (it wasn't part of libbb, so I just copied the files
+ straight in and ripped out uninteresting functions such as
+ md5sum_main, etc.)
+
+2002-03-05 Carl Worth <cworth@east.isi.edu>
+
+ * pkg.c (pkg_print_field): Added support for printing Conffiles
+ field.
+
+ * ipkg_install.c (remove_obsolesced_files): With the fixed
+ pkg_get_installed_files_list from below, this function now seems
+ to work!
+ (ipkg_install_pkg): Fixed to mark old package as uninstalled after
+ upgrading.
+
+ * pkg.c (pkg_get_installed_files_list): Fixed so that it's
+ possible to get an "installed_files" list even from an uninstalled
+ package, (it pulls the list of data files straight out of the
+ package).
+
+ * ipkg_cmd.c (ipkg_upgrade_cmd): Fixed ipkg_upgrade to not choke
+ if asked to upgrade an un-installed package.
+ (ipkg_upgrade_pkg): Fixed printing of version numbers.
+
+ * file_util.c (file_mkdir_hier): Abstracted call to libbb
+ make_directory into new file_mkdir_hier. At this point, the only
+ calls into libbb are isolated in file_util and pkg_extract. This
+ will make it easier if we ever decide to directly incorporate that
+ code or rewrite it.
+
+ * pkg_extract.c (pkg_extract_data_files_to_dir): Abstracted all
+ calls to deb_extract in several new pkg_extract functions.
+
+2002-03-04 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_conf.c (ipkg_conf_init): Added support to ipkg_conf to
+ pickup command-line arguments for "force-defaults" and
+ "force-depends". Things set on the command-line should take
+ precedence over things found in the configuration file.
+
+ * ipkg_cmd.c (ipkg_search_cmd): Fixed formatting of "ipkg search"
+ output.
+
+ * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies):
+ Re-added fix to set *unresolved to NULL if depends is NULL.
+
+ * xregex.c (xregexec): Removed useless error messages from NOMATCH
+ calls to regexec.
+
+ * ipkg_install.c (satisfy_dependencies_for): Added support for new
+ "unresolved" argument in
+ pkg_hash_fetch_unsatisfied_dependencies. Cleaned up warning/error
+ messages.
+
+ * ipkg_cmd.c (ipkg_search_cmd): Implemented first-cut of "ipkg search".
+
+ * pkg_depends.c (pkg_hash_fetch_unsatisfied_dependencies): Fixed
+ to set *unresolved to NULL if depends is NULL.
+
+2002-03-01 Carl Worth <cworth@east.isi.edu>
+
+ * RELEASED ipkg-unstable 0.98.0
+
+ * ipkg_configure.c (ipkg_configure): Added flushing of stdout,
+ (here and in a few other modules).
+
+ * file_util.c (file_copy): Implemented this function here as one
+ step toward isolating the calls into libbb functions. Updated old
+ copy_file calls to file_copy in both ipkg_download.c and
+ ipkg_install.c.
+
+ * ipkg_install.c, ipkg_remove.c: Demoted several "XXX" comments to
+ DPKG_INCOMPATIBILITY as I really don't intend on addressing them
+ any time soon, (if ever).
+
+ * ipkg_cmd.c (ipkg_files_cmd): Fixed "ipkg files" from crashing on
+ uninstalled packages.
+
+ * familiar/rules: Added support for easy building of an
+ ipkg.ipk. The version number and the architecture are
+ automatically sucked in correctly from autoconf magic, (even when
+ cross-compiling). Maybe autoconf will start paying off with
+ benefits rather than pain, (finally!).
+
+ * configure.ac: Removed MEMCMP and STAT checks which were breaking
+ cross-compilation.
+
+ * ipkg_cmd.c (ipkg_upgrade_pkg): BIG bugfix: Package version
+ comparison was sign-reversed, (hence it would never upgrade).
+
+2002-02-28 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_download.c (ipkg_download): Changed from
+ system("/bin/cp",...) to copy_file(...)
+
+ * replace/strndup.c: Implemented an (untested) replacement for
+ strndup.
+
+ * configure.ac: Added AC_CANONICAL_HOST to automatically set the
+ correct architecture type in the ipkg control file.
+
+ * configure.ac: Changed version number to 0.98.0 in preparation
+ for alpha release.
+
+ * familiar/rules: Added support for easy building of an ipkg.ipk.
+
+2002-02-27 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_install.c (ipkg_install_pkg): Fixed to abort on failed
+ download.
+
+ * pkg.c (pkg_run_script): Fixed bug that was preventing any
+ package maintainer scripts from running, (hence, they run now so
+ running non-native offline no longer works until I figure out the
+ chroot plans).
+
+ * TODO: Added rough outline of remaining features with a release
+ schedule.
+
+ * pkg_parse.c (pkg_parse_raw): Added parsing of "MD5Sum" in
+ addition to "MD5sum" to accomodate bug in old ipkg.
+
+ * void_list.c (void_list_remove): Added new remove function, (also
+ adjusts a forward iterator). Required new list->pre_head member
+ which was added to all sub-list types.
+
+ * pkg.c (pkg_init): Changed pkg->conffiles to be of the new
+ conffile_list_t datatype.
+ (pkg_remove_installed_files_list): Pulled this function into
+ pkg.c, (from ipkg_remove.c), so the mallocs and frees would be in
+ the same C file.
+ (pkg_get_conffile): Added this convenience function.
+
+ * ipkg_remove.c: Fixed several bugs. ipkg_remove now actually
+ works for simple packages!
+
+ * ipkg_install.c (ipkg_install_pkg): Don't re-install if a package
+ is already installed.
+ (ipkg_install_pkg): Fixed major bug that all of ipkg_install's
+ work was always being unwound even when successful.
+
+ * ipkg_cmd.c (ipkg_files_cmd): Fixed to use
+ pkg_get_installed_files_list rather than a private implementation
+ that sifted through the file lists on disk.
+
+ * str_util.c (str_ends_with): Added this convenient function.
+ (str_chomp): Another convenience.
+
+ * ipkg_conf.c: Moved chomp to str_util.c (str_chomp), since
+ someone else wanted it too.
+
+2002-02-26 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_parse.c (pkg_parse_raw): Added XXX requesting parsing of
+ Conffiles: field along with a hint about how to store the data.
+
+ * conffile_list.c: Added a little wrapper around nv_pair_list
+
+ * conffile.c: Added a little wrapper around nv_pair
+
+ * str_util.c (str_ends_with): New convenience function.
+
+ * str_list.c (str_list_remove): Plugged in remove function.
+
+ * void_list.c (void_list_remove): Added remove function, (handles
+ updating of forward iterator).
+
+ * pkg.c (pkg_run_script): Changed to return return value of
+ script.
+
+ * ipkg_remove.c: Fleshed out initial version of all ipkg_remove.c
+ functions.
+
+ * ipkg_configure.c (ipkg_configure): Added check on return value
+ of pkg_run script. Added comments about dpkg compliance.
+
+ * ipkg_cmd.c (ipkg_purge_cmd): Added ipkg_purge_cmd
+
+2002-02-20 Carl Worth <cworth@east.isi.edu>
+
+ * Added USC copyright statements, (and Compaq stubs as necessary)
+
+ * ipkg_install.c: At this point "ipkg install" on a simple
+ package, (no scripts and no dependencies), works just fine. It
+ might even do some of the script and dependency handling correctly
+ too, but I haven't tested that yet. "ipkg install libc6" is a nice
+ little test that should complete without any errors or
+ warnings. Follow that up with "ipkg status" to see that it worked.
+
+ * pkg.c (pkg_run_script): Added convenience method for running
+ package scripts.
+
+ * ipkg_install.c: Fixed several bugs:
+ (unpack_pkg_control_files): control files now extract to the
+ correct temporary directory.
+ (ipkg_install_pkg): pkg->state_want is now properly set to SW_INSTALL
+ (ipkg_install_pkg): status file now gets written after installation
+ (cleanup_temporary_files): All temporary files are cleaned up.
+
+ * ipkg_configure.c (ipkg_configure): Fleshed out a very simple
+ ipkg_configure, (simply runs "postinst configure"). Maybe it will
+ need to be smarter at some point. Moved unwritten conffiles stuff
+ back to ipkg_install.c.
+
+ * ipkg_conf.c (ipkg_conf_write_status_files): Moved this function
+ from ipkg_utils to ipkg_conf since it needs access to the
+ pkg_dest_list.
+
+ * pkg_vec.c (marry_two_packages): Added several missing fields,
+ (state_want, state_flag, filename, local_filename, tmp_unpack_dir,
+ md5sum, size, installed_size, priority, source, conffiles,
+ isntalled_files, essential)
+
+2002-02-19 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_install.c: several little bug fixes. "ipkg install" will
+ now actually install files from a package! There are still some
+ bugs, (eg. postinst scripts are not called -- probably other
+ things as well). But, it's coming together now.
+
+ * pkg_dest.c (pkg_dest_init): now creates all necessary directories
+
+ * ipkg_download.c (ipkg_download): Fixed misleading parameter name.
+
+ * ipkg_conf.c (ipkg_conf_deinit): Now cleans up tmd_dir on deinit
+ ipkg.c: now calls ipkg_conf_deinit before exiting.
+ (ipkg_conf_add_nv): Fixed to set default_dest when parsing first
+ dest in ipkg.conf
+
+ * ipkg_cmd.c (ipkg_list_cmd): Fixed ugly bug in ipkg_list that led
+ to infinite loops, segfaults, string corruption, and other bizarre
+ behavior.
+
+ * Added many files as we are approaching the first functional ipkg
+ implementation in C:
+ file_util.c: convenience for testing if file_exists, reading files, etc.
+ ipkg_configure.c: mostly just a stub so far
+ ipkg_download.c: convenient function to download a file
+ nv_pair.c: data structure to hold a name-value pair
+ nv_pair_list.c: data structure to hold a list of nv_pair_t
+ pkg_dest.c: data structure for everything a pkg destination wants
+ pkg_dest_list.c: data structure to hold a list of pkg_dest_t
+ pkg_extract.c: convenience functions for package extraction,
+ (these function should encapsulate any libbb borrowings we perform
+ -- although some slipped into other files already)
+ pkg_src.c: everything you might need for a pkg src.
+ pkg_src_list.c: data structure to hold a list of pkg_src_t
+ str_list.c: data structure to hold a list of char *
+ void_list.c: generic linked-list data structure and functions
+ xsystem.c: wrapper around system() with error checking
+
+ * ipkg_remove.c: Just added some stubs. Nothing really works at
+ all yet.
+
+ * ipkg_install.c: Large rework of ipkg_install. It's now close to
+ actually being usable, (but it's not quite there yet). Revamped to
+ match dpkg install order more closely, (with all the stubs in case
+ we ever want to call all the scripts that dpkg does). Also updated
+ to use a more recent deb_extract from libbb.
+
+ * ipkg_extract_test.c (main): Added support for a third arg, (the
+ filename to extract to the buffer).
+
+ * ipkg_conf.c (ipkg_conf_init): Added several fields to
+ ipkg_conf_t: pkg_src_list, pkg_dest_list ,
+ restrict_to_default_dest, default_dest, tmp_dir, lists_dir,
+ pending_dir, force_depends, and pkg_hash. There's still a bit of
+ tension between options stored in the config file, (ipkg_conf_t),
+ and command-line arguments, (args_t).
+
+ * ipkg_cmd.c: First version that is approaching usability. The
+ following commands are more-or-less in place: "ipkg update", "ipkg
+ list", "ipkg info", "ipkg status". While the rest are in various
+ states of being partiallyy written or written but untested.
+ (ipkg_upgrade_cmd): Added support for restricting to a dest. Many
+ other changes, largely involving plugging into the pkg_hash for
+ real for the first time, and adding multiple dest support.
+
+ * ipkg.c: Added support for setting the dest on the command-line.
+
+ * args.c: Added support for IPKG_CONF_DIR environment variable and
+ -f, -conf, and -conf-file options.
+
+ * configure.ac: Added lots of little bits suggested by autoscan.
+
+2002-02-18 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_parse.c (pkg_parse_raw): Added parsing, (kinda ugly), for
+ essential field.
+ * pkg.c (pkg_print_field): Added the essential flag.
+
+ * pkg_vec.c (pkg_vec_insert): Fixed to use pkg_compare_versions to
+ determine matching versions instead of a strcmp on the version
+ string.
+
+2002-02-15 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_parse.c (pkg_parse_raw): Updated to accept a pkg_src_t
+
+ * pkg.c (pkg_init): Added field to pkg_t: "pkg_src_t *src"
+
+ * pkg_hash.c (pkg_hash_add_from_file): Updated to accept a pkg_src_t
+
+ * pkg_parse.c (parseStatus): Modified to accept a pkg_t *
+ (parseVersion): Added this function
+ (pkg_parse_raw): Updated to accept a pkg_dest_t
+ (pkg_parse_raw): Reworked the parsing to use a pkg_t rather than a
+ slew of local variables.
+ (pkg_parse_raw): Added support for about a dozen new pkg_t fields
+
+ * pkg.h: Updated for all pkg.c changes.
+
+ * pkg.c (pkg_new): Added pkg_new for convenient alloc'ing of a pkg_t.
+ (pkg_init): Added several fields to pkg_t: dest, section,
+ suggests, filename, local_filename, tmp_unpack_dir, md5sum, size,
+ installed_size, priority, source, and conffiles.
+ (): Moved buildPkg this function to pkg_parse
+ (pkg_init_from_file): Added convenience function for filling a
+ pkg_t from an actual package file.
+ (pkg_print_info): Split print_pkg into both pkg_print_info and
+ pkg_print_status.
+ (pkg_print_field): Added pkg_print_field, (extremely ugly)
+ (): Moved parseversion to pkg_parse where it belongs
+ (pkg_version_str_alloc): Added, (complement of parse_version)
+
+ * pkg_depends.h: Added GPL blurb
+ (PKG_DEPENDS_H): Added multiple include protection
+
+ * pkg_depends.c: Moved non-static prototypes to header file.
+ Changed several locl-only functions to be static.
+ Added function prototypes for static functions.
+ (buildDepends): Removed unecessary cast of malloc return value.
+
+ * pkg_hash.h: Moved hash-related struct declarations to this file
+ Rename pkg_fetch* to have consistent pkg_hash_fetch prefix.
+ Added missing prototype for pkg_vec_fetch_by_name
+
+ * pkg_hash.c: (pkg_hash_add_from_file): Added support for setting
+ the pkg_dest
+ (pkg_hash_add_from_file): Moved buildDepends call to
+ hash_insert_pkg
+ (pkg_hash_fetch_installed_by_name_dest): Added this function to
+ support pkg_dest
+
+ * ipkg_utils.h: Added GPL blurb
+ (IPKG_UTILS_H): Added multiple include protection
+
+ * ipkg_utils.c:
+ (read_raw_pkgs_from_file): broke read_raw_pkgs into
+ read_raw_pkgs_from_file and read_raw-pkgs_from_stream
+ (ipkg_write_status_file): Fixed return value
+ (print_pkg_status): Moved this function to pkg.c:pkg_print_status
+ (line_is_blank): Fixed const char handling
+
+2002-02-08 Carl Worth <cworth@east.isi.edu>
+
+ * pkg_parse.c: Fixed a bug in parsing the 3 state fields.
+
+2002-02-06 Carl Worth <cworth@east.isi.edu>
+
+ * pkg.c: Expanded pkg_status field to the full 3 fields: state_want,
+ state_flag, and state_status.
+
+2001-12-11 Carl Worth <cworth@east.isi.edu>
+
+ * ipkg_conf.c: Now parses /etc/ipkg.conf, (and doesn't do anything
+ with it).
+
+ * ipkg.c: Started work on ipkg main, (not much here yet).
+
+ * ipkg_cmd.h: Added a tiny thing to abstract top-level ipkg
+ commands, (not finished).
+
+ * Set up autoconf and friends
diff --git a/src/INSTALL b/src/INSTALL
new file mode 100644
index 0000000..3350a01
--- /dev/null
+++ b/src/INSTALL
@@ -0,0 +1,196 @@
+opkg uses autoconf and friends for configuration. The familiar steps of:
+
+ ./configure
+ make
+
+should be sufficient, (you may need an initial ./autoconfigure.sh), if
+you don't have a generated configure script, (ie. you're compiling a
+version out of CVS).
+
+The remainder of this document is the standard INSTALL document
+provided by autoconf.
+
+-Carl <cworth@handhelds.org>
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..26f2d99
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,37 @@
+ACLOCAL_AMFLAGS = -I shave
+
+SUBDIRS = libbb libopkg src tests utils man
+
+
+HOST_CPU=@host_cpu@
+BUILD_CPU=@build_cpu@
+OPKGLIBDIR=@opkglibdir@
+ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DDATADIR=\"@datadir@\"
+
+PATHFINDER_CFLAGS = @PATHFINDER_CFLAGS@
+PATHFINDER_LIBS = @PATHFINDER_LIBS@
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libopkg.pc
+
+
+
+interceptdir = $(datadir)/opkg/intercept
+intercept_DATA = intercept/ldconfig intercept/depmod intercept/update-modules
+
+install-data-hook:
+ chmod +x $(DESTDIR)$(datadir)/opkg/intercept/*
+
+EXTRA_DIST = $(intercept_DATA)
+
+MAINTAINERCLEANFILES= \
+ configure \
+ Makefile.in \
+ config.guess \
+ config.sub \
+ ltmain.sh \
+ .Makefile.am.swp \
+ aclocal.m4
+
+package: all-recursive
+ STRIPPROG=$(STRIP) INSTALL=$$PWD/install-sh binary-arch
diff --git a/src/NEWS b/src/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/NEWS
diff --git a/src/README b/src/README
new file mode 100644
index 0000000..cf20f1f
--- /dev/null
+++ b/src/README
@@ -0,0 +1,12 @@
+OPKG Package Management System
+==============================
+
+Opkg is a lightweight package management system based on Ipkg.
+
+Website: http://code.google.com/p/opkg/
+Mailing list: http://groups.google.com/group/opkg-devel
+Bug tracker: http://code.google.com/p/opkg/issues/list
+
+The previous website can still be found at:
+http://wiki.openmoko.org/wiki/Opkg
+
diff --git a/src/TODO b/src/TODO
new file mode 100644
index 0000000..0777b1c
--- /dev/null
+++ b/src/TODO
@@ -0,0 +1,42 @@
+
+See issue list: http://code.google.com/p/opkg/issues/list
+
+
+ * Regression test suite.
+
+ * Fix comments marked "XXX".
+
+ * Clean up out of date comments.
+
+ * Consistent indentation.
+
+ * Propagate errors up the call stack. In particular, unarchive.c fails to do
+ this. Errors and error messages must be usable by libopkg frontends.
+ Don't try to use errno after its been clobbered by other libc calls.
+
+ * Remove dead and duplicate code. Refactor duplicated functionality.
+
+ * Remove pkg_info_preinstall_check().
+
+ * Reduce memory used per pkg_t and peak memory use in general.
+
+ * #includes are a mess.
+
+ * Refactor opkg_install_pkg() into more precise functions.
+
+ * pkg_hash_fetch_best_installation_candidate() is linear search O(P*PN)
+ and is slow (frequently called).
+ P provider
+ PN pkgs in a provider
+ It can be O(P) if a hash table is used.
+
+ * Update libbb.
+
+
+
+FEATURES
+
+ * Start with all "XXX: FEATURE" comments. Remove them if they are bogus.
+
+ * Improve dpkg compatibility, according to the Debian Policy Manual.
+ http://www.debian.org/doc/debian-policy/ch-controlfields.html
diff --git a/src/autogen.sh b/src/autogen.sh
new file mode 100755
index 0000000..95b5fba
--- /dev/null
+++ b/src/autogen.sh
@@ -0,0 +1,5 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+glib-gettextize --force --copy || exit 1
+./configure "$@"
+
diff --git a/src/configure.ac b/src/configure.ac
new file mode 100644
index 0000000..ac5a035
--- /dev/null
+++ b/src/configure.ac
@@ -0,0 +1,297 @@
+# Process this file with autoconf to produce a configure script
+AC_INIT([opkg], [0.1.8])
+AC_CONFIG_SRCDIR([libopkg/pkg.c])
+
+AC_CONFIG_AUX_DIR([conf])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_MACRO_DIR([shave])
+
+AM_INIT_AUTOMAKE
+AM_CONFIG_HEADER(libopkg/config.h)
+
+AC_CANONICAL_HOST
+AC_GNU_SOURCE
+
+# Disable C++/Fortran checks
+define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])
+define([AC_LIBTOOL_LANG_F77_CONFIG], [:])
+
+
+for top_builddir in . .. ../.. $ac_auxdir $ac_auxdir/..; do
+ test -f $top_builddir/configure && break
+done
+
+# large file support can be useful for gpgme
+AC_SYS_LARGEFILE
+
+
+# Checks for programs
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AM_PROG_INSTALL_STRIP
+AC_PROG_LIBTOOL
+PKG_PROG_PKG_CONFIG([0.20])
+
+# Checks for libraries
+
+dnl extra argument: --enable-pathfinder
+AC_ARG_ENABLE(pathfinder,
+ AC_HELP_STRING([--enable-pathfinder], [Enable libpathfinder support.
+ [[default=no]] ]),
+ [want_pathfinder="$enableval"], [want_pathfinder="no"])
+dnl Check for libpathfinder
+if test "x$want_pathfinder" = "xyes"; then
+ PKG_CHECK_MODULES([PATHFINDER], [pathfinder-openssl dbus-1 openssl])
+ if test -n "$PATHFINDER_CFLAGS$PATHFINDER_LIBS"; then
+ AC_DEFINE(HAVE_PATHFINDER, 1, [we have pathfinder])
+ fi
+ AC_SUBST(PATHFINDER_CFLAGS)
+ AC_SUBST(PATHFINDER_LIBS)
+fi
+AM_CONDITIONAL(HAVE_PATHFINDER, test "x$want_pathfinder" = "xyes")
+
+# check for libcurl
+AC_ARG_ENABLE(curl,
+ AC_HELP_STRING([--enable-curl], [Enable downloading with curl
+ [[default=yes]] ]),
+ [want_curl="$enableval"], [want_curl="yes"])
+
+if test "x$want_curl" = "xyes"; then
+ PKG_CHECK_MODULES(CURL, [libcurl])
+ AC_DEFINE(HAVE_CURL, 1, [Define if you want CURL support])
+fi
+
+# check for sha256
+AC_ARG_ENABLE(sha256,
+ AC_HELP_STRING([--enable-sha256], [Enable sha256sum check
+ (sha256.{c,h} are GPLv3 licensed) [[default=no]] ]),
+ [want_sha256="$enableval"], [want_sha256="no"])
+
+if test "x$want_sha256" = "xyes"; then
+ AC_DEFINE(HAVE_SHA256, 1, [Define if you want sha256 support])
+fi
+AM_CONDITIONAL(HAVE_SHA256, test "x$want_sha256" = "xyes")
+
+# check for openssl
+AC_ARG_ENABLE(openssl,
+ AC_HELP_STRING([--enable-openssl], [Enable signature checking with OpenSSL
+ [[default=no]] ]),
+ [want_openssl="$enableval"], [want_openssl="no"])
+
+if test "x$want_openssl" = "xyes"; then
+ AC_DEFINE(HAVE_OPENSSL, 1, [Define if you want OpenSSL support])
+ NEED_SSL_LIBS="yes"
+fi
+
+# check for libssl-curl
+AC_ARG_ENABLE(ssl-curl,
+ AC_HELP_STRING([--enable-ssl-curl], [Enable certificate authentication with curl
+ [[default="yes"]] ]),
+ [want_sslcurl="$enableval"], [want_sslcurl="yes"])
+
+if test "x$want_curl" = "xyes" -a "x$want_sslcurl" = "xyes"; then
+ AC_DEFINE(HAVE_CURL, 1, [Define if you want CURL support])
+ AC_DEFINE(HAVE_SSLCURL, 1, [Define if you want certificate authentication with curl])
+ NEED_SSL_LIBS="yes"
+fi
+
+if test "x$NEED_SSL_LIBS" = "xyes"; then
+ AC_MSG_CHECKING([if openssl is available])
+
+ PKG_CHECK_MODULES(OPENSSL, openssl, [:], [:])
+ if test "x$OPENSSL_LIBS" != "x"; then
+ AC_MSG_RESULT(yes)
+ else
+ OPENSSL_LIBS="-lcrypto -lssl"
+ dnl If pkg-config fails, run compile/link test.
+ AC_TRY_LINK([
+#include <openssl/opensslv.h>
+], [
+return OPENSSL_VERSION_NUMBER; ],
+ [
+ AC_MSG_RESULT(yes)
+
+ ], [
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR(OpenSSL not found)
+ ])
+ fi
+ AC_SUBST(OPENSSL_LIBS)
+fi
+
+
+dnl **********
+dnl GPGME
+dnl **********
+
+AC_ARG_ENABLE(gpg,
+ AC_HELP_STRING([--enable-gpg], [Enable signature checking with gpgme
+ [[default=yes]] ]),
+ [want_gpgme="$enableval"], [want_gpgme="yes"])
+
+if test "x$want_gpgme" = "xyes"; then
+ ok="no"
+ min_gpgme_version=1.0.0
+ AC_PATH_PROG(GPGME_CONFIG, gpgme-config, "failed")
+ if test $GPGME_CONFIG != "failed" ; then
+ AC_MSG_CHECKING(for GPGME - version >= $min_gpgme_version)
+ req_major=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ req_minor=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ req_micro=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ gpgme_config_version=`$GPGME_CONFIG --version`
+ major=`echo $gpgme_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
+ minor=`echo $gpgme_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
+ micro=`echo $gpgme_config_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
+
+ if test "$major" -eq "$req_major"; then
+ if test "$minor" -ge "$req_minor"; then
+ if test "$micro" -ge "$req_micro"; then
+ ok="yes"
+ fi
+ fi
+ fi
+ fi
+
+ if test $ok = "yes"; then
+ GPGME_CFLAGS=`$GPGME_CONFIG --cflags`
+ GPGME_LIBS=`$GPGME_CONFIG --libs`
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_GPGME, 1, [Define if you want GPG support])
+ else
+ AC_MSG_ERROR(GPGME $min_gpgme_version or later needed)
+ fi
+fi
+
+AC_SUBST(GPGME_CFLAGS)
+AC_SUBST(GPGME_LIBS)
+
+
+# Checks for header files
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS([errno.h fcntl.h memory.h regex.h stddef.h stdlib.h string.h strings.h unistd.h utime.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_UID_T
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_CHECK_MEMBERS([struct stat.st_rdev])
+
+# Checks endianness
+AC_C_BIGENDIAN(BIGENDIAN_CFLAGS="-DWORDS_BIGENDIAN=1",)
+AC_SUBST(BIGENDIAN_CFLAGS)
+
+# Don't do annoying tests that don't work when cross-compiling, just trust them.
+# The AC_FUNC_MEMCMP test doesn't work during a cross-compile, disable.
+# AC_FUNC_MEMCMP
+# The AC_FUNC_STAT test doesn't work during a cross-compile, disable.
+# AC_FUNC_STAT
+
+# Checks for library functions
+AC_FUNC_CHOWN
+AC_FUNC_FORK
+AC_TYPE_SIGNAL
+AC_FUNC_UTIME_NULL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS([memmove memset mkdir regcomp strchr strcspn strdup strerror strndup strrchr strstr strtol strtoul sysinfo utime])
+
+opkglibdir=
+AC_ARG_WITH(opkglibdir,
+[ --with-opkglibdir=DIR specifies directory to put status and info files.
+ "/opkg" is always added so if you want your files
+ to be in /var/lib/opkg instead of /usr/lib/opkg
+ you should indicate
+ --with-opkglibdir=/var/lib ],
+[case "${withval}" in
+yes) AC_MSG_ERROR(bad value ${withval} given for opkg libs directories ) ;;
+no) ;;
+*) opkglibdir=$with_opkglibdir ;;
+esac])
+
+# Default local prefix if it is empty
+if test x$opkglibdir = x; then
+ opkglibdir=/usr/lib
+fi
+
+opkgetcdir=
+AC_ARG_WITH(opkgetcdir,
+[ --with-opkgetcdir=DIR specifies directory for opkg.conf file,
+ "/opkg" is always added so if you want your files
+ to be in /usr/etc/opkg instead of /etc/opkg
+ you should indicate
+ --with-opkgetcdir=/usr/etc ],
+[case "${withval}" in
+yes) AC_MSG_ERROR(bad value ${withval} given for opkg.conf directory ) ;;
+no) ;;
+*) opkgetcdir=$with_opkgetcdir ;;
+esac])
+
+# Default local prefix if it is empty
+if test x$opkgetcdir = x; then
+ opkgetcdir=/etc
+fi
+
+opkglockfile=
+AC_ARG_WITH(opkglockfile,
+[ --with-opkglockfile=FILE specifies the file used to make sure there is only
+ one instance of opkg runnning.
+ Defaults to ${opkglibdir}/opkg/lock, i.e.
+ /usr/lib/opkg/lock ],
+[case "${withval}" in
+yes) AC_MSG_ERROR(bad value ${withval} given for opkg lock file ) ;;
+no) ;;
+*) opkglockfile=$with_opkglockfile ;;
+esac])
+
+# Default if empty
+if test x$opkglockfile = x; then
+ opkglockfile=${opkglibdir}/opkg/lock
+fi
+
+dnl Some special cases for the wow64 build
+if test "x$want_gpgme" = "xyes"
+then
+ if test "x$want_openssl" = "xyes"
+ then
+ AC_MSG_ERROR([--enable-gpg and --enable-openssl are mutually exclusive.
+Use --disable-gpg if you want OpenSSL smime signatures])
+ fi
+fi
+
+CLEAN_DATE=`date +"%B %Y" | tr -d '\n'`
+
+AC_SUBST(opkglibdir)
+AC_SUBST(opkgetcdir)
+AC_SUBST(opkglockfile)
+AC_SUBST([CLEAN_DATE])
+
+# Setup output beautifier.
+SHAVE_INIT([shave], [enable])
+
+AC_OUTPUT(
+ Makefile
+ libopkg/Makefile
+ tests/Makefile
+ src/Makefile
+ libbb/Makefile
+ utils/Makefile
+ utils/update-alternatives
+ libopkg.pc
+ shave/shave
+ shave/shave-libtool
+ man/Makefile
+ man/opkg-cl.1
+ man/opkg-key.1
+ )
diff --git a/src/etc/.svn/all-wcprops b/src/etc/.svn/all-wcprops
new file mode 100644
index 0000000..f2c5c68
--- /dev/null
+++ b/src/etc/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 26
+/svn/!svn/ver/35/trunk/etc
+END
diff --git a/src/etc/.svn/entries b/src/etc/.svn/entries
new file mode 100644
index 0000000..119d205
--- /dev/null
+++ b/src/etc/.svn/entries
@@ -0,0 +1,28 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/etc
+http://opkg.googlecode.com/svn
+
+
+
+2008-12-15T04:44:59.793641Z
+35
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
diff --git a/src/familiar/.svn/all-wcprops b/src/familiar/.svn/all-wcprops
new file mode 100644
index 0000000..0a197af
--- /dev/null
+++ b/src/familiar/.svn/all-wcprops
@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 31
+/svn/!svn/ver/43/trunk/familiar
+END
diff --git a/src/familiar/.svn/entries b/src/familiar/.svn/entries
new file mode 100644
index 0000000..83a5336
--- /dev/null
+++ b/src/familiar/.svn/entries
@@ -0,0 +1,28 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/familiar
+http://opkg.googlecode.com/svn
+
+
+
+2008-12-15T04:52:22.947717Z
+43
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
diff --git a/src/intercept/.svn/all-wcprops b/src/intercept/.svn/all-wcprops
new file mode 100644
index 0000000..0c6bb69
--- /dev/null
+++ b/src/intercept/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 33
+/svn/!svn/ver/599/trunk/intercept
+END
+ldconfig
+K 25
+svn:wc:ra_dav:version-url
+V 40
+/svn/!svn/ver/8/trunk/intercept/ldconfig
+END
+update-modules
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svn/!svn/ver/8/trunk/intercept/update-modules
+END
+depmod
+K 25
+svn:wc:ra_dav:version-url
+V 40
+/svn/!svn/ver/599/trunk/intercept/depmod
+END
diff --git a/src/intercept/.svn/entries b/src/intercept/.svn/entries
new file mode 100644
index 0000000..9a8d6c2
--- /dev/null
+++ b/src/intercept/.svn/entries
@@ -0,0 +1,130 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/intercept
+http://opkg.googlecode.com/svn
+
+
+
+2011-02-02T00:53:46.722527Z
+599
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
+ldconfig
+file
+
+
+
+
+2012-02-03T08:11:57.139042Z
+7c6a3e9a69d12051c8408d5219d0475f
+2008-12-15T04:18:06.332473Z
+8
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+151
+
+update-modules
+file
+
+
+
+
+2012-02-03T08:11:57.139042Z
+ae529fb0a3053604d6a7ace02680fcaa
+2008-12-15T04:18:06.332473Z
+8
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+175
+
+depmod
+file
+
+
+
+
+2012-02-03T08:11:57.139042Z
+79516947e97ecd71c163e4f751e5c736
+2011-02-02T00:53:46.722527Z
+599
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+309
+
diff --git a/src/intercept/.svn/text-base/depmod.svn-base b/src/intercept/.svn/text-base/depmod.svn-base
new file mode 100644
index 0000000..f8a4f9a
--- /dev/null
+++ b/src/intercept/.svn/text-base/depmod.svn-base
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ "x$1" = "x-a" ] || [ "x$1" = "x-A" ]; then
+ echo "depmod $@" >> $OPKG_INTERCEPT_DIR/depmod
+ sort -u $OPKG_INTERCEPT_DIR/depmod > $OPKG_INTERCEPT_DIR/depmod.tmp
+ mv $OPKG_INTERCEPT_DIR/depmod.tmp $OPKG_INTERCEPT_DIR/depmod
+ chmod +x $OPKG_INTERCEPT_DIR/depmod
+ exit 0
+fi
+
+/sbin/depmod $*
+
diff --git a/src/intercept/.svn/text-base/ldconfig.svn-base b/src/intercept/.svn/text-base/ldconfig.svn-base
new file mode 100644
index 0000000..e07c81d
--- /dev/null
+++ b/src/intercept/.svn/text-base/ldconfig.svn-base
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if [ ! -f $OPKG_INTERCEPT_DIR/ldconfig ]; then
+ echo "ldconfig" > $OPKG_INTERCEPT_DIR/ldconfig
+ chmod +x $OPKG_INTERCEPT_DIR/ldconfig
+fi
+
diff --git a/src/intercept/.svn/text-base/update-modules.svn-base b/src/intercept/.svn/text-base/update-modules.svn-base
new file mode 100644
index 0000000..ac5749c
--- /dev/null
+++ b/src/intercept/.svn/text-base/update-modules.svn-base
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if [ ! -f $OPKG_INTERCEPT_DIR/update-modules ]; then
+ echo "update-modules" > $OPKG_INTERCEPT_DIR/update-modules
+ chmod +x $OPKG_INTERCEPT_DIR/update-modules
+fi
+
diff --git a/src/intercept/depmod b/src/intercept/depmod
new file mode 100644
index 0000000..f8a4f9a
--- /dev/null
+++ b/src/intercept/depmod
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ "x$1" = "x-a" ] || [ "x$1" = "x-A" ]; then
+ echo "depmod $@" >> $OPKG_INTERCEPT_DIR/depmod
+ sort -u $OPKG_INTERCEPT_DIR/depmod > $OPKG_INTERCEPT_DIR/depmod.tmp
+ mv $OPKG_INTERCEPT_DIR/depmod.tmp $OPKG_INTERCEPT_DIR/depmod
+ chmod +x $OPKG_INTERCEPT_DIR/depmod
+ exit 0
+fi
+
+/sbin/depmod $*
+
diff --git a/src/intercept/ldconfig b/src/intercept/ldconfig
new file mode 100644
index 0000000..e07c81d
--- /dev/null
+++ b/src/intercept/ldconfig
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if [ ! -f $OPKG_INTERCEPT_DIR/ldconfig ]; then
+ echo "ldconfig" > $OPKG_INTERCEPT_DIR/ldconfig
+ chmod +x $OPKG_INTERCEPT_DIR/ldconfig
+fi
+
diff --git a/src/intercept/update-modules b/src/intercept/update-modules
new file mode 100644
index 0000000..ac5749c
--- /dev/null
+++ b/src/intercept/update-modules
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if [ ! -f $OPKG_INTERCEPT_DIR/update-modules ]; then
+ echo "update-modules" > $OPKG_INTERCEPT_DIR/update-modules
+ chmod +x $OPKG_INTERCEPT_DIR/update-modules
+fi
+
diff --git a/src/libbb/.svn/all-wcprops b/src/libbb/.svn/all-wcprops
new file mode 100644
index 0000000..8791632
--- /dev/null
+++ b/src/libbb/.svn/all-wcprops
@@ -0,0 +1,113 @@
+K 25
+svn:wc:ra_dav:version-url
+V 29
+/svn/!svn/ver/604/trunk/libbb
+END
+wfopen.c
+K 25
+svn:wc:ra_dav:version-url
+V 36
+/svn/!svn/ver/3/trunk/libbb/wfopen.c
+END
+safe_strncpy.c
+K 25
+svn:wc:ra_dav:version-url
+V 44
+/svn/!svn/ver/552/trunk/libbb/safe_strncpy.c
+END
+gz_open.c
+K 25
+svn:wc:ra_dav:version-url
+V 39
+/svn/!svn/ver/604/trunk/libbb/gz_open.c
+END
+make_directory.c
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svn/!svn/ver/552/trunk/libbb/make_directory.c
+END
+copy_file_chunk.c
+K 25
+svn:wc:ra_dav:version-url
+V 45
+/svn/!svn/ver/3/trunk/libbb/copy_file_chunk.c
+END
+all_read.c
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svn/!svn/ver/3/trunk/libbb/all_read.c
+END
+unzip.c
+K 25
+svn:wc:ra_dav:version-url
+V 37
+/svn/!svn/ver/577/trunk/libbb/unzip.c
+END
+xfuncs.c
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svn/!svn/ver/552/trunk/libbb/xfuncs.c
+END
+copy_file.c
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/314/trunk/libbb/copy_file.c
+END
+mode_string.c
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/3/trunk/libbb/mode_string.c
+END
+parse_mode.c
+K 25
+svn:wc:ra_dav:version-url
+V 42
+/svn/!svn/ver/552/trunk/libbb/parse_mode.c
+END
+libbb.h
+K 25
+svn:wc:ra_dav:version-url
+V 37
+/svn/!svn/ver/471/trunk/libbb/libbb.h
+END
+xreadlink.c
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/552/trunk/libbb/xreadlink.c
+END
+concat_path_file.c
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svn/!svn/ver/3/trunk/libbb/concat_path_file.c
+END
+unarchive.c
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/594/trunk/libbb/unarchive.c
+END
+time_string.c
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/3/trunk/libbb/time_string.c
+END
+Makefile.am
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/471/trunk/libbb/Makefile.am
+END
+last_char_is.c
+K 25
+svn:wc:ra_dav:version-url
+V 44
+/svn/!svn/ver/552/trunk/libbb/last_char_is.c
+END
diff --git a/src/libbb/.svn/entries b/src/libbb/.svn/entries
new file mode 100644
index 0000000..41b68e6
--- /dev/null
+++ b/src/libbb/.svn/entries
@@ -0,0 +1,640 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/libbb
+http://opkg.googlecode.com/svn
+
+
+
+2011-02-18T00:02:14.770648Z
+604
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
+wfopen.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+4de9274e149c9a721486612d912f010c
+2008-12-15T04:10:56.746937Z
+3
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1156
+
+safe_strncpy.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+eceb9fe63523c56418c814398928b131
+2010-08-18T03:39:02.973664Z
+552
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1187
+
+gz_open.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+25bb2e8fa8654800a1ca67a27e9a3b7c
+2011-02-18T00:02:14.770648Z
+604
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3463
+
+make_directory.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+0ac335573a0abb1fd2923b9c0d0badc7
+2010-08-18T03:39:02.973664Z
+552
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2212
+
+copy_file_chunk.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+1ba798a3be6f8a446b8bef279c12150a
+2008-12-15T04:10:56.746937Z
+3
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1797
+
+all_read.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+7e29f8b6acbdbf28acc550e5714283e9
+2008-12-15T04:10:56.746937Z
+3
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2043
+
+unzip.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+696d797a25573d1258b184f3443a369c
+2010-11-11T00:23:29.781328Z
+577
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+28342
+
+xfuncs.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+05055d1a1df58a0ca92a8c5ce0c2c6d2
+2010-08-18T03:39:02.973664Z
+552
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1990
+
+copy_file.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+0e4fab1c48fd3c4a9ac3ddced1e3e697
+2009-11-16T00:43:40.210441Z
+314
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5801
+
+mode_string.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+0e327b4639db752764fc893f325380f3
+2008-12-15T04:10:56.746937Z
+3
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1987
+
+parse_mode.c
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+b52917e30e6adccb57ff822d1dd89e54
+2010-08-18T03:39:02.973664Z
+552
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3090
+
+libbb.h
+file
+
+
+
+
+2012-02-03T08:11:57.563042Z
+3e39fa5e5256c01d96d53c1177adf48c
+2009-12-09T01:20:03.840165Z
+471
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3492
+
+xreadlink.c
+file
+
+
+
+
+2012-02-03T08:11:57.567042Z
+565265da2163aabe44fc349dc0b9d6f8
+2010-08-18T03:39:02.973664Z
+552
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+696
+
+concat_path_file.c
+file
+
+
+
+
+2012-02-03T08:11:57.567042Z
+db5612f5d02a74764abeae502e1b8eb0
+2008-12-15T04:10:56.746937Z
+3
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1364
+
+time_string.c
+file
+
+
+
+
+2012-02-03T08:11:57.567042Z
+c9f00cb228ef5a4d60ea217d1c47240e
+2008-12-15T04:10:56.746937Z
+3
+ticktock35
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1455
+
+unarchive.c
+file
+
+
+
+
+2012-02-03T08:11:57.567042Z
+8cdd4c13dbfab8cb27aa3157ff1387c0
+2010-12-23T01:38:25.615032Z
+594
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+21712
+
+Makefile.am
+file
+
+
+
+
+2012-02-03T08:11:57.567042Z
+48cbb7a82fb7cb54cc39bcf02666fe82
+2009-12-09T01:20:03.840165Z
+471
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+495
+
+last_char_is.c
+file
+
+
+
+
+2012-02-03T08:11:57.567042Z
+caea3b90b5b195dfcb1bd10e75a4078c
+2010-08-18T03:39:02.973664Z
+552
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1260
+
diff --git a/src/libbb/.svn/text-base/Makefile.am.svn-base b/src/libbb/.svn/text-base/Makefile.am.svn-base
new file mode 100644
index 0000000..1cc82df
--- /dev/null
+++ b/src/libbb/.svn/text-base/Makefile.am.svn-base
@@ -0,0 +1,26 @@
+HOST_CPU=@host_cpu@
+BUILD_CPU=@build_cpu@
+ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@
+
+noinst_LTLIBRARIES = libbb.la
+
+libbb_la_SOURCES = gz_open.c \
+ libbb.h \
+ unzip.c \
+ wfopen.c \
+ unarchive.c \
+ copy_file.c \
+ copy_file_chunk.c \
+ xreadlink.c \
+ concat_path_file.c \
+ xfuncs.c \
+ last_char_is.c \
+ make_directory.c \
+ safe_strncpy.c \
+ parse_mode.c \
+ time_string.c \
+ all_read.c \
+ mode_string.c
+
+libbb_la_CFLAGS = $(ALL_CFLAGS)
+#libbb_la_LDFLAGS = -static
diff --git a/src/libbb/.svn/text-base/all_read.c.svn-base b/src/libbb/.svn/text-base/all_read.c.svn-base
new file mode 100644
index 0000000..6ec731a
--- /dev/null
+++ b/src/libbb/.svn/text-base/all_read.c.svn-base
@@ -0,0 +1,83 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libbb.h"
+
+extern void archive_xread_all(int fd , char *buf, size_t count)
+{
+ ssize_t size;
+
+ size = full_read(fd, buf, count);
+ if (size != count) {
+ perror_msg_and_die("Short read");
+ }
+ return;
+}
+
+/*
+ * Read all of the supplied buffer from a file.
+ * This does multiple reads as necessary.
+ * Returns the amount read, or -1 on an error.
+ * A short read is returned on an end of file.
+ */
+ssize_t full_read(int fd, char *buf, int len)
+{
+ ssize_t cc;
+ ssize_t total;
+
+ total = 0;
+
+ while (len > 0) {
+ cc = safe_read(fd, buf, len);
+
+ if (cc < 0)
+ return cc; /* read() returns -1 on failure. */
+
+ if (cc == 0)
+ break;
+
+ buf = ((char *)buf) + cc;
+ total += cc;
+ len -= cc;
+ }
+
+ return total;
+}
+
+
+ssize_t safe_read(int fd, void *buf, size_t count)
+{
+ ssize_t n;
+
+ do {
+ n = read(fd, buf, count);
+ } while (n < 0 && errno == EINTR);
+
+ return n;
+}
+
+
+
+/* END CODE */
+
diff --git a/src/libbb/.svn/text-base/concat_path_file.c.svn-base b/src/libbb/.svn/text-base/concat_path_file.c.svn-base
new file mode 100644
index 0000000..e62b99e
--- /dev/null
+++ b/src/libbb/.svn/text-base/concat_path_file.c.svn-base
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/* concatenate path and file name to new allocation buffer,
+ * not addition '/' if path name already have '/'
+*/
+
+#include <string.h>
+#include "libbb.h"
+
+extern char *concat_path_file(const char *path, const char *filename)
+{
+ char *outbuf;
+ char *lc;
+
+ if (!path)
+ path="";
+ lc = last_char_is(path, '/');
+ while (*filename == '/')
+ filename++;
+ outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL));
+ sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename);
+
+ return outbuf;
+}
diff --git a/src/libbb/.svn/text-base/copy_file.c.svn-base b/src/libbb/.svn/text-base/copy_file.c.svn-base
new file mode 100644
index 0000000..fb76669
--- /dev/null
+++ b/src/libbb/.svn/text-base/copy_file.c.svn-base
@@ -0,0 +1,231 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini copy_file implementation for busybox
+ *
+ *
+ * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libbb.h"
+
+int copy_file(const char *source, const char *dest, int flags)
+{
+ struct stat source_stat;
+ struct stat dest_stat;
+ int dest_exists = 1;
+ int status = 0;
+
+ if (((flags & FILEUTILS_PRESERVE_SYMLINKS) &&
+ lstat(source, &source_stat) < 0) ||
+ (!(flags & FILEUTILS_PRESERVE_SYMLINKS) &&
+ stat(source, &source_stat) < 0)) {
+ perror_msg("%s", source);
+ return -1;
+ }
+
+ if (stat(dest, &dest_stat) < 0) {
+ if (errno != ENOENT) {
+ perror_msg("unable to stat `%s'", dest);
+ return -1;
+ }
+ dest_exists = 0;
+ }
+
+ if (dest_exists && source_stat.st_rdev == dest_stat.st_rdev &&
+ source_stat.st_ino == dest_stat.st_ino) {
+ error_msg("`%s' and `%s' are the same file", source, dest);
+ return -1;
+ }
+
+ if (S_ISDIR(source_stat.st_mode)) {
+ DIR *dp;
+ struct dirent *d;
+ mode_t saved_umask = 0;
+
+ if (!(flags & FILEUTILS_RECUR)) {
+ error_msg("%s: omitting directory", source);
+ return -1;
+ }
+
+ /* Create DEST. */
+ if (dest_exists) {
+ if (!S_ISDIR(dest_stat.st_mode)) {
+ error_msg("`%s' is not a directory", dest);
+ return -1;
+ }
+ } else {
+ mode_t mode;
+ saved_umask = umask(0);
+
+ mode = source_stat.st_mode;
+ if (!(flags & FILEUTILS_PRESERVE_STATUS))
+ mode = source_stat.st_mode & ~saved_umask;
+ mode |= S_IRWXU;
+
+ if (mkdir(dest, mode) < 0) {
+ umask(saved_umask);
+ perror_msg("cannot create directory `%s'", dest);
+ return -1;
+ }
+
+ umask(saved_umask);
+ }
+
+ /* Recursively copy files in SOURCE. */
+ if ((dp = opendir(source)) == NULL) {
+ perror_msg("unable to open directory `%s'", source);
+ status = -1;
+ goto end;
+ }
+
+ while ((d = readdir(dp)) != NULL) {
+ char *new_source, *new_dest;
+
+ if (strcmp(d->d_name, ".") == 0 ||
+ strcmp(d->d_name, "..") == 0)
+ continue;
+
+ new_source = concat_path_file(source, d->d_name);
+ new_dest = concat_path_file(dest, d->d_name);
+ if (copy_file(new_source, new_dest, flags) < 0)
+ status = -1;
+ free(new_source);
+ free(new_dest);
+ }
+
+ /* ??? What if an error occurs in readdir? */
+
+ if (closedir(dp) < 0) {
+ perror_msg("unable to close directory `%s'", source);
+ status = -1;
+ }
+
+ if (!dest_exists &&
+ chmod(dest, source_stat.st_mode & ~saved_umask) < 0) {
+ perror_msg("unable to change permissions of `%s'", dest);
+ status = -1;
+ }
+ } else if (S_ISREG(source_stat.st_mode)) {
+ FILE *sfp, *dfp;
+
+ if (dest_exists) {
+ if ((dfp = fopen(dest, "w")) == NULL) {
+ if (!(flags & FILEUTILS_FORCE)) {
+ perror_msg("unable to open `%s'", dest);
+ return -1;
+ }
+
+ if (unlink(dest) < 0) {
+ perror_msg("unable to remove `%s'", dest);
+ return -1;
+ }
+
+ dest_exists = 0;
+ }
+ }
+
+ if (!dest_exists) {
+ int fd;
+
+ if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 ||
+ (dfp = fdopen(fd, "w")) == NULL) {
+ if (fd >= 0)
+ close(fd);
+ perror_msg("unable to open `%s'", dest);
+ return -1;
+ }
+ }
+
+ if ((sfp = fopen(source, "r")) == NULL) {
+ fclose(dfp);
+ perror_msg("unable to open `%s'", source);
+ status = -1;
+ goto end;
+ }
+
+ if (copy_file_chunk(sfp, dfp, -1) < 0)
+ status = -1;
+
+ if (fclose(dfp) < 0) {
+ perror_msg("unable to close `%s'", dest);
+ status = -1;
+ }
+
+ if (fclose(sfp) < 0) {
+ perror_msg("unable to close `%s'", source);
+ status = -1;
+ }
+ } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
+ S_ISSOCK(source_stat.st_mode)) {
+ if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
+ perror_msg("unable to create `%s'", dest);
+ return -1;
+ }
+ } else if (S_ISFIFO(source_stat.st_mode)) {
+ if (mkfifo(dest, source_stat.st_mode) < 0) {
+ perror_msg("cannot create fifo `%s'", dest);
+ return -1;
+ }
+ } else if (S_ISLNK(source_stat.st_mode)) {
+ char *lpath = xreadlink(source);
+ if (symlink(lpath, dest) < 0) {
+ perror_msg("cannot create symlink `%s'", dest);
+ return -1;
+ }
+ free(lpath);
+
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+ if (flags & FILEUTILS_PRESERVE_STATUS)
+ if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
+ perror_msg("unable to preserve ownership of `%s'", dest);
+#endif
+ return 0;
+ } else {
+ error_msg("internal error: unrecognized file type");
+ return -1;
+ }
+
+end:
+
+ if (flags & FILEUTILS_PRESERVE_STATUS) {
+ struct utimbuf times;
+
+ times.actime = source_stat.st_atime;
+ times.modtime = source_stat.st_mtime;
+ if (utime(dest, &times) < 0)
+ perror_msg("unable to preserve times of `%s'", dest);
+ if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
+ source_stat.st_mode &= ~(S_ISUID | S_ISGID);
+ perror_msg("unable to preserve ownership of `%s'", dest);
+ }
+ if (chmod(dest, source_stat.st_mode) < 0)
+ perror_msg("unable to preserve permissions of `%s'", dest);
+ }
+
+ return status;
+}
diff --git a/src/libbb/.svn/text-base/copy_file_chunk.c.svn-base b/src/libbb/.svn/text-base/copy_file_chunk.c.svn-base
new file mode 100644
index 0000000..63d2ab1
--- /dev/null
+++ b/src/libbb/.svn/text-base/copy_file_chunk.c.svn-base
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include "libbb.h"
+
+/* Copy CHUNKSIZE bytes (or until EOF if CHUNKSIZE equals -1) from SRC_FILE
+ * to DST_FILE. */
+extern int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize)
+{
+ size_t nread, nwritten, size;
+ char buffer[BUFSIZ];
+
+ while (chunksize != 0) {
+ if (chunksize > BUFSIZ)
+ size = BUFSIZ;
+ else
+ size = chunksize;
+
+ nread = fread (buffer, 1, size, src_file);
+
+ if (nread != size && ferror (src_file)) {
+ perror_msg ("read");
+ return -1;
+ } else if (nread == 0) {
+ if (chunksize != -1) {
+ error_msg ("Unable to read all data");
+ return -1;
+ }
+
+ return 0;
+ }
+
+ nwritten = fwrite (buffer, 1, nread, dst_file);
+
+ if (nwritten != nread) {
+ if (ferror (dst_file))
+ perror_msg ("write");
+ else
+ error_msg ("Unable to write all data");
+ return -1;
+ }
+
+ if (chunksize != -1)
+ chunksize -= nwritten;
+ }
+
+ return 0;
+}
diff --git a/src/libbb/.svn/text-base/gz_open.c.svn-base b/src/libbb/.svn/text-base/gz_open.c.svn-base
new file mode 100644
index 0000000..bdc7564
--- /dev/null
+++ b/src/libbb/.svn/text-base/gz_open.c.svn-base
@@ -0,0 +1,149 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "libbb.h"
+
+static int gz_use_vfork;
+
+FILE *
+gz_open(FILE *compressed_file, int *pid)
+{
+ int unzip_pipe[2];
+ off_t floc;
+ int cfile = -1;
+
+ gz_use_vfork = (getenv("OPKG_USE_VFORK") != NULL);
+
+ if (gz_use_vfork) {
+ /* Create a new file descriptor for the input stream
+ * (it *must* be associated with a file), and lseek()
+ * to the same position in that fd as the stream.
+ */
+ cfile = dup(fileno(compressed_file));
+ floc = ftello(compressed_file);
+ lseek(cfile, floc, SEEK_SET);
+ setenv("GZIP", "--quiet", 0);
+ }
+
+ if (pipe(unzip_pipe)!=0) {
+ perror_msg("pipe");
+ return(NULL);
+ }
+
+ /* If we don't flush, we end up with two copies of anything pending,
+ one from the parent, one from the child */
+ fflush(stdout);
+ fflush(stderr);
+
+ if (gz_use_vfork) {
+ *pid = vfork();
+ } else {
+ *pid = fork();
+ }
+
+ if (*pid<0) {
+ perror_msg("fork");
+ return(NULL);
+ }
+
+ if (*pid==0) {
+ /* child process */
+ close(unzip_pipe[0]);
+ if (gz_use_vfork) {
+ dup2(unzip_pipe[1], 1);
+ dup2(cfile, 0);
+ execlp("gunzip","gunzip",NULL);
+ /* If we get here, we had a failure */
+ _exit(EXIT_FAILURE);
+ } else {
+ unzip(compressed_file, fdopen(unzip_pipe[1], "w"));
+ fflush(NULL);
+ fclose(compressed_file);
+ close(unzip_pipe[1]);
+ _exit(EXIT_SUCCESS);
+ }
+ }
+ /* Parent process is executing here */
+ if (gz_use_vfork) {
+ close(cfile);
+ }
+ close(unzip_pipe[1]);
+ return(fdopen(unzip_pipe[0], "r"));
+}
+
+int
+gz_close(int gunzip_pid)
+{
+ int status;
+ int ret;
+
+ if (gz_use_vfork) {
+ /* The gunzip process remains running in the background if we
+ * used the vfork()/exec() technique - so we have to kill it
+ * forcibly. There might be a better way to do this, but that
+ * affect a lot of other parts of opkg, and this works fine.
+ */
+ if (kill(gunzip_pid, SIGTERM) == -1) {
+ perror_msg("gz_close(): unable to kill gunzip pid.");
+ return -1;
+ }
+ }
+
+
+ if (waitpid(gunzip_pid, &status, 0) == -1) {
+ perror_msg("waitpid");
+ return -1;
+ }
+
+ if (gz_use_vfork) {
+ /* Bail out here if we used the vfork()/exec() technique. */
+ return 0;
+ }
+
+ if (WIFSIGNALED(status)) {
+ error_msg("Unzip process killed by signal %d.\n",
+ WTERMSIG(status));
+ return -1;
+ }
+
+ if (!WIFEXITED(status)) {
+ /* shouldn't happen */
+ error_msg("Your system is broken: got status %d from waitpid.\n",
+ status);
+ return -1;
+ }
+
+ if ((ret = WEXITSTATUS(status))) {
+ error_msg("Unzip process failed with return code %d.\n",
+ ret);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/libbb/.svn/text-base/last_char_is.c.svn-base b/src/libbb/.svn/text-base/last_char_is.c.svn-base
new file mode 100644
index 0000000..26c2423
--- /dev/null
+++ b/src/libbb/.svn/text-base/last_char_is.c.svn-base
@@ -0,0 +1,40 @@
+/*
+ * busybox library eXtended function
+ *
+ * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <string.h>
+#include "libbb.h"
+
+/* Find out if the last character of a string matches the one given Don't
+ * underrun the buffer if the string length is 0. Also avoids a possible
+ * space-hogging inline of strlen() per usage.
+ */
+char * last_char_is(const char *s, int c)
+{
+ char *sret;
+ if (!s)
+ return NULL;
+ sret = (char *)s+strlen(s)-1;
+ if (sret>=s && *sret == c) {
+ return sret;
+ } else {
+ return NULL;
+ }
+}
diff --git a/src/libbb/.svn/text-base/libbb.h.svn-base b/src/libbb/.svn/text-base/libbb.h.svn-base
new file mode 100644
index 0000000..4e1fafc
--- /dev/null
+++ b/src/libbb/.svn/text-base/libbb.h.svn-base
@@ -0,0 +1,123 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox main internal header file
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __LIBBB_H__
+#define __LIBBB_H__ 1
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <netdb.h>
+
+#include "../libopkg/opkg_message.h"
+
+#ifndef FALSE
+#define FALSE ((int) 0)
+#endif
+
+#ifndef TRUE
+#define TRUE ((int) 1)
+#endif
+
+#define error_msg(fmt, args...) opkg_msg(ERROR, fmt"\n", ##args)
+#define perror_msg(fmt, args...) opkg_perror(ERROR, fmt, ##args)
+#define error_msg_and_die(fmt, args...) \
+ do { \
+ error_msg(fmt, ##args); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+#define perror_msg_and_die(fmt, args...) \
+ do { \
+ perror_msg(fmt, ##args); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+
+extern void archive_xread_all(int fd, char *buf, size_t count);
+
+const char *mode_string(int mode);
+const char *time_string(time_t timeVal);
+
+int copy_file(const char *source, const char *dest, int flags);
+int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize);
+ssize_t safe_read(int fd, void *buf, size_t count);
+ssize_t full_read(int fd, char *buf, int len);
+
+extern int parse_mode( const char* s, mode_t* theMode);
+
+extern FILE *wfopen(const char *path, const char *mode);
+extern FILE *xfopen(const char *path, const char *mode);
+
+extern void *xmalloc (size_t size);
+extern void *xrealloc(void *old, size_t size);
+extern void *xcalloc(size_t nmemb, size_t size);
+extern char *xstrdup (const char *s);
+extern char *xstrndup (const char *s, int n);
+extern char *safe_strncpy(char *dst, const char *src, size_t size);
+
+char *xreadlink(const char *path);
+char *concat_path_file(const char *path, const char *filename);
+char *last_char_is(const char *s, int c);
+
+typedef struct file_headers_s {
+ char *name;
+ char *link_name;
+ off_t size;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+ time_t mtime;
+ dev_t device;
+} file_header_t;
+
+enum extract_functions_e {
+ extract_verbose_list = 1,
+ extract_list = 2,
+ extract_one_to_buffer = 4,
+ extract_to_stream = 8,
+ extract_all_to_fs = 16,
+ extract_preserve_date = 32,
+ extract_data_tar_gz = 64,
+ extract_control_tar_gz = 128,
+ extract_unzip_only = 256,
+ extract_unconditional = 512,
+ extract_create_leading_dirs = 1024,
+ extract_quiet = 2048,
+ extract_exclude_list = 4096
+};
+
+char *deb_extract(const char *package_filename, FILE *out_stream,
+ const int extract_function, const char *prefix,
+ const char *filename, int *err);
+
+extern int unzip(FILE *l_in_file, FILE *l_out_file);
+extern int gz_close(int gunzip_pid);
+extern FILE *gz_open(FILE *compressed_file, int *pid);
+
+int make_directory (const char *path, long mode, int flags);
+
+enum {
+ FILEUTILS_PRESERVE_STATUS = 1,
+ FILEUTILS_PRESERVE_SYMLINKS = 2,
+ FILEUTILS_RECUR = 4,
+ FILEUTILS_FORCE = 8,
+};
+
+#endif /* __LIBBB_H__ */
diff --git a/src/libbb/.svn/text-base/make_directory.c.svn-base b/src/libbb/.svn/text-base/make_directory.c.svn-base
new file mode 100644
index 0000000..86ab554
--- /dev/null
+++ b/src/libbb/.svn/text-base/make_directory.c.svn-base
@@ -0,0 +1,80 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini make_directory implementation for busybox
+ *
+ * Copyright (C) 2001 Matt Kraai.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libgen.h>
+
+#include "libbb.h"
+
+/* Create the directory PATH with mode MODE, or the default if MODE is -1.
+ * Also create parent directories as necessary if flags contains
+ * FILEUTILS_RECUR. */
+
+int make_directory (const char *path, long mode, int flags)
+{
+ if (!(flags & FILEUTILS_RECUR)) {
+ if (mkdir (path, 0777) < 0) {
+ perror_msg ("Cannot create directory `%s'", path);
+ return -1;
+ }
+
+ if (mode != -1 && chmod (path, mode) < 0) {
+ perror_msg ("Cannot set permissions of directory `%s'", path);
+ return -1;
+ }
+ } else {
+ struct stat st;
+
+ if (stat (path, &st) < 0 && errno == ENOENT) {
+ int status;
+ char *pathcopy, *parent, *parentcopy;
+ mode_t mask;
+
+ mask = umask (0);
+ umask (mask);
+
+ /* dirname is unsafe, it may both modify the
+ memory of the path argument and may return
+ a pointer to static memory, which can then
+ be modified by consequtive calls to dirname */
+
+ pathcopy = xstrdup (path);
+ parent = dirname (pathcopy);
+ parentcopy = xstrdup (parent);
+ status = make_directory (parentcopy, (0777 & ~mask)
+ | 0300, FILEUTILS_RECUR);
+ free (pathcopy);
+ free (parentcopy);
+
+
+ if (status < 0 || make_directory (path, mode, 0) < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/libbb/.svn/text-base/mode_string.c.svn-base b/src/libbb/.svn/text-base/mode_string.c.svn-base
new file mode 100644
index 0000000..12dc179
--- /dev/null
+++ b/src/libbb/.svn/text-base/mode_string.c.svn-base
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+
+
+
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+
+/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
+static const mode_t SBIT[] = {
+ 0, 0, S_ISUID,
+ 0, 0, S_ISGID,
+ 0, 0, S_ISVTX
+};
+
+/* The 9 mode bits to test */
+static const mode_t MBIT[] = {
+ S_IRUSR, S_IWUSR, S_IXUSR,
+ S_IRGRP, S_IWGRP, S_IXGRP,
+ S_IROTH, S_IWOTH, S_IXOTH
+};
+
+static const char MODE1[] = "rwxrwxrwx";
+static const char MODE0[] = "---------";
+static const char SMODE1[] = "..s..s..t";
+static const char SMODE0[] = "..S..S..T";
+
+/*
+ * Return the standard ls-like mode string from a file mode.
+ * This is static and so is overwritten on each call.
+ */
+const char *mode_string(int mode)
+{
+ static char buf[12];
+
+ int i;
+
+ buf[0] = TYPECHAR(mode);
+ for (i = 0; i < 9; i++) {
+ if (mode & SBIT[i])
+ buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
+ else
+ buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
+ }
+ return buf;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/.svn/text-base/parse_mode.c.svn-base b/src/libbb/.svn/text-base/parse_mode.c.svn-base
new file mode 100644
index 0000000..02668c7
--- /dev/null
+++ b/src/libbb/.svn/text-base/parse_mode.c.svn-base
@@ -0,0 +1,134 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+
+/* This function parses the sort of string you might pass
+ * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the
+ * correct mode described by the string. */
+extern int parse_mode(const char *s, mode_t * theMode)
+{
+ static const mode_t group_set[] = {
+ S_ISUID | S_IRWXU, /* u */
+ S_ISGID | S_IRWXG, /* g */
+ S_IRWXO, /* o */
+ S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */
+ };
+
+ static const mode_t mode_set[] = {
+ S_IRUSR | S_IRGRP | S_IROTH, /* r */
+ S_IWUSR | S_IWGRP | S_IWOTH, /* w */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* x */
+ S_ISUID | S_ISGID, /* s */
+ S_ISVTX /* t */
+ };
+
+ static const char group_chars[] = "ugoa";
+ static const char mode_chars[] = "rwxst";
+
+ const char *p;
+
+ mode_t andMode =
+ S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+ mode_t orMode = 0;
+ mode_t mode;
+ mode_t groups;
+ char type;
+ char c;
+
+ if (s==NULL) {
+ return (FALSE);
+ }
+
+ do {
+ mode = 0;
+ groups = 0;
+ NEXT_GROUP:
+ if ((c = *s++) == '\0') {
+ return -1;
+ }
+ for (p=group_chars ; *p ; p++) {
+ if (*p == c) {
+ groups |= group_set[(int)(p-group_chars)];
+ goto NEXT_GROUP;
+ }
+ }
+ switch (c) {
+ case '=':
+ case '+':
+ case '-':
+ type = c;
+ if (groups == 0) { /* The default is "all" */
+ groups |= S_ISUID | S_ISGID | S_ISVTX
+ | S_IRWXU | S_IRWXG | S_IRWXO;
+ }
+ break;
+ default:
+ if ((c < '0') || (c > '7') || (mode | groups)) {
+ return (FALSE);
+ } else {
+ *theMode = strtol(--s, NULL, 8);
+ return (TRUE);
+ }
+ }
+
+ NEXT_MODE:
+ if (((c = *s++) != '\0') && (c != ',')) {
+ for (p=mode_chars ; *p ; p++) {
+ if (*p == c) {
+ mode |= mode_set[(int)(p-mode_chars)];
+ goto NEXT_MODE;
+ }
+ }
+ break; /* We're done so break out of loop.*/
+ }
+ switch (type) {
+ case '=':
+ andMode &= ~(groups); /* Now fall through. */
+ case '+':
+ orMode |= mode & groups;
+ break;
+ case '-':
+ andMode &= ~(mode & groups);
+ orMode &= ~(mode & groups);
+ break;
+ }
+ } while (c == ',');
+
+ *theMode &= andMode;
+ *theMode |= orMode;
+
+ return TRUE;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/.svn/text-base/safe_strncpy.c.svn-base b/src/libbb/.svn/text-base/safe_strncpy.c.svn-base
new file mode 100644
index 0000000..eb2dbab
--- /dev/null
+++ b/src/libbb/.svn/text-base/safe_strncpy.c.svn-base
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include "libbb.h"
+
+
+
+/* Like strncpy but make sure the resulting string is always 0 terminated. */
+extern char * safe_strncpy(char *dst, const char *src, size_t size)
+{
+ dst[size-1] = '\0';
+ return strncpy(dst, src, size-1);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/.svn/text-base/time_string.c.svn-base b/src/libbb/.svn/text-base/time_string.c.svn-base
new file mode 100644
index 0000000..d103a02
--- /dev/null
+++ b/src/libbb/.svn/text-base/time_string.c.svn-base
@@ -0,0 +1,62 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <utime.h>
+#include "libbb.h"
+
+
+/*
+ * Return the standard ls-like time string from a time_t
+ * This is static and so is overwritten on each call.
+ */
+const char *time_string(time_t timeVal)
+{
+ time_t now;
+ char *str;
+ static char buf[26];
+
+ time(&now);
+
+ str = ctime(&timeVal);
+
+ strcpy(buf, &str[4]);
+ buf[12] = '\0';
+
+ if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
+ strcpy(&buf[7], &str[20]);
+ buf[11] = '\0';
+ }
+
+ return buf;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/.svn/text-base/unarchive.c.svn-base b/src/libbb/.svn/text-base/unarchive.c.svn-base
new file mode 100644
index 0000000..5d4464f
--- /dev/null
+++ b/src/libbb/.svn/text-base/unarchive.c.svn-base
@@ -0,0 +1,784 @@
+/*
+ * Copyright (C) 2000 by Glenn McGrath
+ * Copyright (C) 2001 by Laurence Anderson
+ *
+ * Based on previous work by busybox developers and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <libgen.h>
+
+#include "libbb.h"
+
+#define CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY 1
+#define CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+
+#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+static char *longname = NULL;
+static char *linkname = NULL;
+#endif
+
+off_t archive_offset;
+
+#define SEEK_BUF 4096
+static ssize_t
+seek_by_read(FILE* fd, size_t len)
+{
+ ssize_t cc, total = 0;
+ char buf[SEEK_BUF];
+
+ while (len) {
+ cc = fread(buf, sizeof(buf[0]),
+ len > SEEK_BUF ? SEEK_BUF : len,
+ fd);
+
+ total += cc;
+ len -= cc;
+
+ if(feof(fd) || ferror(fd))
+ break;
+ }
+ return total;
+}
+
+static void
+seek_sub_file(FILE *fd, const int count)
+{
+ archive_offset += count;
+
+ /* Do not use fseek() on a pipe. It may fail with ESPIPE, leaving the
+ * stream at an undefined location.
+ */
+ seek_by_read(fd, count);
+
+ return;
+}
+
+
+/* Extract the data postioned at src_stream to either filesystem, stdout or
+ * buffer depending on the value of 'function' which is defined in libbb.h
+ *
+ * prefix doesnt have to be just a directory, it may prefix the filename as well.
+ *
+ * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath
+ * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have
+ * 'dpkg.' as their prefix
+ *
+ * For this reason if prefix does point to a dir then it must end with a
+ * trailing '/' or else the last dir will be assumed to be the file prefix
+ */
+static char *
+extract_archive(FILE *src_stream, FILE *out_stream,
+ const file_header_t *file_entry, const int function,
+ const char *prefix,
+ int *err)
+{
+ FILE *dst_stream = NULL;
+ char *full_name = NULL;
+ char *full_link_name = NULL;
+ char *buffer = NULL;
+ struct utimbuf t;
+
+ *err = 0;
+
+ /* prefix doesnt have to be a proper path it may prepend
+ * the filename as well */
+ if (prefix != NULL) {
+ /* strip leading '/' in filename to extract as prefix may not be dir */
+ /* Cant use concat_path_file here as prefix might not be a directory */
+ char *path = file_entry->name;
+ if (strncmp("./", path, 2) == 0) {
+ path += 2;
+ if (strlen(path) == 0)
+ /* Do nothing, current dir already exists. */
+ return NULL;
+ }
+ full_name = xmalloc(strlen(prefix) + strlen(path) + 1);
+ strcpy(full_name, prefix);
+ strcat(full_name, path);
+ if ( file_entry->link_name ){
+ full_link_name = xmalloc(strlen(prefix) + strlen(file_entry->link_name) + 1);
+ strcpy(full_link_name, prefix);
+ strcat(full_link_name, file_entry->link_name);
+ }
+ } else {
+ full_name = xstrdup(file_entry->name);
+ if ( file_entry->link_name )
+ full_link_name = xstrdup(file_entry->link_name);
+ }
+
+
+ if (function & extract_to_stream) {
+ if (S_ISREG(file_entry->mode)) {
+ *err = copy_file_chunk(src_stream, out_stream, file_entry->size);
+ archive_offset += file_entry->size;
+ }
+ }
+ else if (function & extract_one_to_buffer) {
+ if (S_ISREG(file_entry->mode)) {
+ buffer = (char *) xmalloc(file_entry->size + 1);
+ fread(buffer, 1, file_entry->size, src_stream);
+ buffer[file_entry->size] = '\0';
+ archive_offset += file_entry->size;
+ goto cleanup;
+ }
+ }
+ else if (function & extract_all_to_fs) {
+ struct stat oldfile;
+ int stat_res;
+ stat_res = lstat (full_name, &oldfile);
+ if (stat_res == 0) { /* The file already exists */
+ if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) {
+ if (!S_ISDIR(oldfile.st_mode)) {
+ unlink(full_name); /* Directories might not be empty etc */
+ }
+ } else {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ error_msg("%s not created: newer or same age file exists", file_entry->name);
+ }
+ seek_sub_file(src_stream, file_entry->size);
+ goto cleanup;
+ }
+ }
+ if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */
+ char *buf, *parent;
+ buf = xstrdup(full_name);
+ parent = dirname(buf);
+ if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ error_msg("couldn't create leading directories");
+ }
+ }
+ free (buf);
+ }
+ switch(file_entry->mode & S_IFMT) {
+ case S_IFREG:
+ if (file_entry->link_name) { /* Found a cpio hard link */
+ if (link(full_link_name, full_name) != 0) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ perror_msg("Cannot link from %s to '%s'",
+ file_entry->name, file_entry->link_name);
+ }
+ }
+ } else {
+ if ((dst_stream = wfopen(full_name, "w")) == NULL) {
+ *err = -1;
+ seek_sub_file(src_stream, file_entry->size);
+ goto cleanup;
+ }
+ archive_offset += file_entry->size;
+ *err = copy_file_chunk(src_stream, dst_stream, file_entry->size);
+ fclose(dst_stream);
+ }
+ break;
+ case S_IFDIR:
+ if (stat_res != 0) {
+ if (mkdir(full_name, file_entry->mode) < 0) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ perror_msg("Cannot make dir %s", full_name);
+ }
+ }
+ }
+ break;
+ case S_IFLNK:
+ if (symlink(file_entry->link_name, full_name) < 0) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name);
+ }
+ goto cleanup;
+ }
+ break;
+ case S_IFSOCK:
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFIFO:
+ if (mknod(full_name, file_entry->mode, file_entry->device) == -1) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ perror_msg("Cannot create node %s", file_entry->name);
+ }
+ goto cleanup;
+ }
+ break;
+ default:
+ *err = -1;
+ perror_msg("Don't know how to handle %s", full_name);
+
+ }
+
+ /* Changing a symlink's properties normally changes the properties of the
+ * file pointed to, so dont try and change the date or mode, lchown does
+ * does the right thing, but isnt available in older versions of libc */
+ if (S_ISLNK(file_entry->mode)) {
+#if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1)
+ lchown(full_name, file_entry->uid, file_entry->gid);
+#endif
+ } else {
+ if (function & extract_preserve_date) {
+ t.actime = file_entry->mtime;
+ t.modtime = file_entry->mtime;
+ utime(full_name, &t);
+ }
+ chown(full_name, file_entry->uid, file_entry->gid);
+ chmod(full_name, file_entry->mode);
+ }
+ } else {
+ /* If we arent extracting data we have to skip it,
+ * if data size is 0 then then just do it anyway
+ * (saves testing for it) */
+ seek_sub_file(src_stream, file_entry->size);
+ }
+
+ /* extract_list and extract_verbose_list can be used in conjunction
+ * with one of the above four extraction functions, so do this seperately */
+ if (function & extract_verbose_list) {
+ fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode),
+ file_entry->uid, file_entry->gid,
+ (int) file_entry->size, time_string(file_entry->mtime));
+ }
+ if ((function & extract_list) || (function & extract_verbose_list)){
+ /* fputs doesnt add a trailing \n, so use fprintf */
+ fprintf(out_stream, "%s\n", file_entry->name);
+ }
+
+cleanup:
+ free(full_name);
+ if ( full_link_name )
+ free(full_link_name);
+
+ return buffer;
+}
+
+static char *
+unarchive(FILE *src_stream, FILE *out_stream,
+ file_header_t *(*get_headers)(FILE *),
+ void (*free_headers)(file_header_t *),
+ const int extract_function,
+ const char *prefix,
+ const char **extract_names,
+ int *err)
+{
+ file_header_t *file_entry;
+ int extract_flag;
+ int i;
+ char *buffer = NULL;
+
+ *err = 0;
+
+ archive_offset = 0;
+ while ((file_entry = get_headers(src_stream)) != NULL) {
+ extract_flag = TRUE;
+
+ if (extract_names != NULL) {
+ int found_flag = FALSE;
+ char *p = file_entry->name;
+
+ if (p[0] == '.' && p[1] == '/')
+ p += 2;
+
+ for(i = 0; extract_names[i] != 0; i++) {
+ if (strcmp(extract_names[i], p) == 0) {
+ found_flag = TRUE;
+ break;
+ }
+ }
+ if (extract_function & extract_exclude_list) {
+ if (found_flag == TRUE) {
+ extract_flag = FALSE;
+ }
+ } else {
+ /* If its not found in the include list dont extract it */
+ if (found_flag == FALSE) {
+ extract_flag = FALSE;
+ }
+ }
+ }
+
+ if (extract_flag == TRUE) {
+ buffer = extract_archive(src_stream, out_stream,
+ file_entry, extract_function,
+ prefix, err);
+ *err = 0; /* XXX: ignore extraction errors */
+ if (*err) {
+ free_headers(file_entry);
+ break;
+ }
+ } else {
+ /* seek past the data entry */
+ seek_sub_file(src_stream, file_entry->size);
+ }
+ free_headers(file_entry);
+ }
+
+ return buffer;
+}
+
+static file_header_t *
+get_header_ar(FILE *src_stream)
+{
+ file_header_t *typed;
+ union {
+ char raw[60];
+ struct {
+ char name[16];
+ char date[12];
+ char uid[6];
+ char gid[6];
+ char mode[8];
+ char size[10];
+ char magic[2];
+ } formated;
+ } ar;
+ static char *ar_long_names;
+
+ if (fread(ar.raw, 1, 60, src_stream) != 60) {
+ return(NULL);
+ }
+ archive_offset += 60;
+ /* align the headers based on the header magic */
+ if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) {
+ /* some version of ar, have an extra '\n' after each data entry,
+ * this puts the next header out by 1 */
+ if (ar.formated.magic[1] != '`') {
+ error_msg("Invalid magic");
+ return(NULL);
+ }
+ /* read the next char out of what would be the data section,
+ * if its a '\n' then it is a valid header offset by 1*/
+ archive_offset++;
+ if (fgetc(src_stream) != '\n') {
+ error_msg("Invalid magic");
+ return(NULL);
+ }
+ /* fix up the header, we started reading 1 byte too early */
+ /* raw_header[60] wont be '\n' as it should, but it doesnt matter */
+ memmove(ar.raw, &ar.raw[1], 59);
+ }
+
+ typed = (file_header_t *) xcalloc(1, sizeof(file_header_t));
+
+ typed->size = (size_t) atoi(ar.formated.size);
+ /* long filenames have '/' as the first character */
+ if (ar.formated.name[0] == '/') {
+ if (ar.formated.name[1] == '/') {
+ /* If the second char is a '/' then this entries data section
+ * stores long filename for multiple entries, they are stored
+ * in static variable long_names for use in future entries */
+ ar_long_names = (char *) xrealloc(ar_long_names, typed->size);
+ fread(ar_long_names, 1, typed->size, src_stream);
+ archive_offset += typed->size;
+ /* This ar entries data section only contained filenames for other records
+ * they are stored in the static ar_long_names for future reference */
+ return (get_header_ar(src_stream)); /* Return next header */
+ } else if (ar.formated.name[1] == ' ') {
+ /* This is the index of symbols in the file for compilers */
+ seek_sub_file(src_stream, typed->size);
+ return (get_header_ar(src_stream)); /* Return next header */
+ } else {
+ /* The number after the '/' indicates the offset in the ar data section
+ (saved in variable long_name) that conatains the real filename */
+ if (!ar_long_names) {
+ error_msg("Cannot resolve long file name");
+ return (NULL);
+ }
+ typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1]));
+ }
+ } else {
+ /* short filenames */
+ typed->name = xcalloc(1, 16);
+ strncpy(typed->name, ar.formated.name, 16);
+ }
+ typed->name[strcspn(typed->name, " /")]='\0';
+
+ /* convert the rest of the now valid char header to its typed struct */
+ parse_mode(ar.formated.mode, &typed->mode);
+ typed->mtime = atoi(ar.formated.date);
+ typed->uid = atoi(ar.formated.uid);
+ typed->gid = atoi(ar.formated.gid);
+
+ return(typed);
+}
+
+static void
+free_header_ar(file_header_t *ar_entry)
+{
+ if (ar_entry == NULL)
+ return;
+
+ free(ar_entry->name);
+ if (ar_entry->link_name)
+ free(ar_entry->link_name);
+
+ free(ar_entry);
+}
+
+
+static file_header_t *
+get_header_tar(FILE *tar_stream)
+{
+ union {
+ unsigned char raw[512];
+ struct {
+ char name[100]; /* 0-99 */
+ char mode[8]; /* 100-107 */
+ char uid[8]; /* 108-115 */
+ char gid[8]; /* 116-123 */
+ char size[12]; /* 124-135 */
+ char mtime[12]; /* 136-147 */
+ char chksum[8]; /* 148-155 */
+ char typeflag; /* 156-156 */
+ char linkname[100]; /* 157-256 */
+ char magic[6]; /* 257-262 */
+ char version[2]; /* 263-264 */
+ char uname[32]; /* 265-296 */
+ char gname[32]; /* 297-328 */
+ char devmajor[8]; /* 329-336 */
+ char devminor[8]; /* 337-344 */
+ char prefix[155]; /* 345-499 */
+ char padding[12]; /* 500-512 */
+ } formated;
+ } tar;
+ file_header_t *tar_entry = NULL;
+ long i;
+ long sum = 0;
+
+ if (archive_offset % 512 != 0) {
+ seek_sub_file(tar_stream, 512 - (archive_offset % 512));
+ }
+
+ if (fread(tar.raw, 1, 512, tar_stream) != 512) {
+ /* Unfortunately its common for tar files to have all sorts of
+ * trailing garbage, fail silently */
+// error_msg("Couldnt read header");
+ return(NULL);
+ }
+ archive_offset += 512;
+
+ /* Check header has valid magic, unfortunately some tar files
+ * have empty (0'ed) tar entries at the end, which will
+ * cause this to fail, so fail silently for now
+ */
+ if (strncmp(tar.formated.magic, "ustar", 5) != 0) {
+#ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY
+ if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0)
+#endif
+ return(NULL);
+ }
+
+ /* Do checksum on headers */
+ for (i = 0; i < 148 ; i++) {
+ sum += tar.raw[i];
+ }
+ sum += ' ' * 8;
+ for (i = 156; i < 512 ; i++) {
+ sum += tar.raw[i];
+ }
+ if (sum != strtol(tar.formated.chksum, NULL, 8)) {
+ if ( strtol(tar.formated.chksum,NULL,8) != 0 )
+ error_msg("Invalid tar header checksum");
+ return(NULL);
+ }
+
+ /* convert to type'ed variables */
+ tar_entry = xcalloc(1, sizeof(file_header_t));
+
+
+
+ // tar_entry->name = xstrdup(tar.formated.name);
+
+/*
+ parse_mode(tar.formated.mode, &tar_entry->mode);
+*/
+ tar_entry->mode = 07777 & strtol(tar.formated.mode, NULL, 8);
+
+ tar_entry->uid = strtol(tar.formated.uid, NULL, 8);
+ tar_entry->gid = strtol(tar.formated.gid, NULL, 8);
+ tar_entry->size = strtol(tar.formated.size, NULL, 8);
+ tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8);
+
+ tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) +
+ strtol(tar.formated.devminor, NULL, 8);
+
+ /* Fix mode, used by the old format */
+ switch (tar.formated.typeflag) {
+ /* hard links are detected as regular files with 0 size and a link name */
+ case '1':
+ tar_entry->mode |= S_IFREG ;
+ break;
+ case 0:
+ case '0':
+
+# ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY
+ if (last_char_is(tar_entry->name, '/')) {
+ tar_entry->mode |= S_IFDIR;
+ } else
+# endif
+ tar_entry->mode |= S_IFREG;
+ break;
+ case '2':
+ tar_entry->mode |= S_IFLNK;
+ break;
+ case '3':
+ tar_entry->mode |= S_IFCHR;
+ break;
+ case '4':
+ tar_entry->mode |= S_IFBLK;
+ break;
+ case '5':
+ tar_entry->mode |= S_IFDIR;
+ break;
+ case '6':
+ tar_entry->mode |= S_IFIFO;
+ break;
+# ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+ case 'L': {
+ longname = xmalloc(tar_entry->size + 1);
+ if(fread(longname, tar_entry->size, 1, tar_stream) != 1)
+ return NULL;
+ longname[tar_entry->size] = '\0';
+ archive_offset += tar_entry->size;
+
+ return(get_header_tar(tar_stream));
+ }
+ case 'K': {
+ linkname = xmalloc(tar_entry->size + 1);
+ if(fread(linkname, tar_entry->size, 1, tar_stream) != 1)
+ return NULL;
+ linkname[tar_entry->size] = '\0';
+ archive_offset += tar_entry->size;
+
+ return(get_header_tar(tar_stream));
+ }
+ case 'D':
+ case 'M':
+ case 'N':
+ case 'S':
+ case 'V':
+ perror_msg("Ignoring GNU extension type %c", tar.formated.typeflag);
+# endif
+ default:
+ perror_msg("Unknown typeflag: 0x%x", tar.formated.typeflag);
+ break;
+
+ }
+
+
+#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+ if (longname) {
+ tar_entry->name = longname;
+ longname = NULL;
+ } else
+#endif
+ {
+ tar_entry->name = xstrndup(tar.formated.name, 100);
+
+ if (tar.formated.prefix[0]) {
+ char *temp = tar_entry->name;
+ char *prefixTemp = xstrndup(tar.formated.prefix, 155);
+ tar_entry->name = concat_path_file(prefixTemp, temp);
+ free(temp);
+ free(prefixTemp);
+ }
+ }
+
+ if (linkname) {
+ tar_entry->link_name = linkname;
+ linkname = NULL;
+ } else
+ {
+ tar_entry->link_name = *tar.formated.linkname != '\0' ?
+ xstrndup(tar.formated.linkname, 100) : NULL;
+ }
+
+ return(tar_entry);
+}
+
+static void
+free_header_tar(file_header_t *tar_entry)
+{
+ if (tar_entry == NULL)
+ return;
+
+ free(tar_entry->name);
+ if (tar_entry->link_name)
+ free(tar_entry->link_name);
+
+ free(tar_entry);
+}
+
+char *
+deb_extract(const char *package_filename, FILE *out_stream,
+ const int extract_function, const char *prefix,
+ const char *filename, int *err)
+{
+ FILE *deb_stream = NULL;
+ file_header_t *ar_header = NULL;
+ const char **file_list = NULL;
+ char *output_buffer = NULL;
+ char *ared_file = NULL;
+ char ar_magic[8];
+ int gz_err;
+
+ *err = 0;
+
+ if (filename != NULL) {
+ file_list = xmalloc(sizeof(char *) * 2);
+ file_list[0] = filename;
+ file_list[1] = NULL;
+ }
+
+ if (extract_function & extract_control_tar_gz) {
+ ared_file = "control.tar.gz";
+ }
+ else if (extract_function & extract_data_tar_gz) {
+ ared_file = "data.tar.gz";
+ } else {
+ opkg_msg(ERROR, "Internal error: extract_function=%x\n",
+ extract_function);
+ *err = -1;
+ goto cleanup;
+ }
+
+ /* open the debian package to be worked on */
+ deb_stream = wfopen(package_filename, "r");
+ if (deb_stream == NULL) {
+ *err = -1;
+ goto cleanup;
+ }
+ /* set the buffer size */
+ setvbuf(deb_stream, NULL, _IOFBF, 0x8000);
+
+ /* check ar magic */
+ fread(ar_magic, 1, 8, deb_stream);
+
+ if (strncmp(ar_magic,"!<arch>",7) == 0) {
+ archive_offset = 8;
+
+ while ((ar_header = get_header_ar(deb_stream)) != NULL) {
+ if (strcmp(ared_file, ar_header->name) == 0) {
+ int gunzip_pid = 0;
+ FILE *uncompressed_stream;
+ /* open a stream of decompressed data */
+ uncompressed_stream = gz_open(deb_stream, &gunzip_pid);
+ if (uncompressed_stream == NULL) {
+ *err = -1;
+ goto cleanup;
+ }
+
+ archive_offset = 0;
+ output_buffer = unarchive(uncompressed_stream,
+ out_stream, get_header_tar,
+ free_header_tar,
+ extract_function, prefix,
+ file_list, err);
+ fclose(uncompressed_stream);
+ gz_err = gz_close(gunzip_pid);
+ if (gz_err)
+ *err = -1;
+ free_header_ar(ar_header);
+ break;
+ }
+ if (fseek(deb_stream, ar_header->size, SEEK_CUR) == -1) {
+ opkg_perror(ERROR, "Couldn't fseek into %s", package_filename);
+ *err = -1;
+ free_header_ar(ar_header);
+ goto cleanup;
+ }
+ free_header_ar(ar_header);
+ }
+ goto cleanup;
+ } else if (strncmp(ar_magic, "\037\213", 2) == 0) {
+ /* it's a gz file, let's assume it's an opkg */
+ int unzipped_opkg_pid;
+ FILE *unzipped_opkg_stream;
+ file_header_t *tar_header;
+ archive_offset = 0;
+ if (fseek(deb_stream, 0, SEEK_SET) == -1) {
+ opkg_perror(ERROR, "Couldn't fseek into %s", package_filename);
+ *err = -1;
+ goto cleanup;
+ }
+ unzipped_opkg_stream = gz_open(deb_stream, &unzipped_opkg_pid);
+ if (unzipped_opkg_stream == NULL) {
+ *err = -1;
+ goto cleanup;
+ }
+
+ /* walk through outer tar file to find ared_file */
+ while ((tar_header = get_header_tar(unzipped_opkg_stream)) != NULL) {
+ int name_offset = 0;
+ if (strncmp(tar_header->name, "./", 2) == 0)
+ name_offset = 2;
+ if (strcmp(ared_file, tar_header->name+name_offset) == 0) {
+ int gunzip_pid = 0;
+ FILE *uncompressed_stream;
+ /* open a stream of decompressed data */
+ uncompressed_stream = gz_open(unzipped_opkg_stream, &gunzip_pid);
+ if (uncompressed_stream == NULL) {
+ *err = -1;
+ goto cleanup;
+ }
+ archive_offset = 0;
+
+ output_buffer = unarchive(uncompressed_stream,
+ out_stream,
+ get_header_tar,
+ free_header_tar,
+ extract_function,
+ prefix,
+ file_list,
+ err);
+
+ free_header_tar(tar_header);
+ fclose(uncompressed_stream);
+ gz_err = gz_close(gunzip_pid);
+ if (gz_err)
+ *err = -1;
+ break;
+ }
+ seek_sub_file(unzipped_opkg_stream, tar_header->size);
+ free_header_tar(tar_header);
+ }
+ fclose(unzipped_opkg_stream);
+ gz_err = gz_close(unzipped_opkg_pid);
+ if (gz_err)
+ *err = -1;
+
+ goto cleanup;
+ } else {
+ *err = -1;
+ error_msg("%s: invalid magic", package_filename);
+ }
+
+cleanup:
+ if (deb_stream)
+ fclose(deb_stream);
+ if (file_list)
+ free(file_list);
+
+ return output_buffer;
+}
diff --git a/src/libbb/.svn/text-base/unzip.c.svn-base b/src/libbb/.svn/text-base/unzip.c.svn-base
new file mode 100644
index 0000000..435effb
--- /dev/null
+++ b/src/libbb/.svn/text-base/unzip.c.svn-base
@@ -0,0 +1,1021 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * gunzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersee@debian.org> to support
+ * files as well as stdin/stdout, and to generally behave itself wrt
+ * command line handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of
+ * standard busybox functions by Glenn McGrath <bug1@optushome.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libbb.h"
+
+static FILE *in_file, *out_file;
+
+static unsigned char *window;
+static unsigned long *crc_table = NULL;
+
+static unsigned long crc; /* shift register contents */
+
+/*
+ * window size--must be a power of two, and
+ * at least 32K for zip's deflate method
+ */
+static const int WSIZE = 0x8000;
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */
+static const int N_MAX = 288; /* maximum number of codes in any set */
+
+static long bytes_out; /* number of output bytes */
+static unsigned long outcnt; /* bytes in output buffer */
+
+static unsigned hufts; /* track memory usage */
+static unsigned long bb; /* bit buffer */
+static unsigned bk; /* bits in bit buffer */
+
+typedef struct huft_s {
+ unsigned char e; /* number of extra bits or operation */
+ unsigned char b; /* number of bits in this code or subcode */
+ union {
+ unsigned short n; /* literal, length base, or distance base */
+ struct huft_s *t; /* pointer to next level of table */
+ } v;
+} huft_t;
+
+static const unsigned short mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+//static int error_number = 0;
+/* ========================================================================
+ * Signal and error handler.
+ */
+
+static void abort_gzip()
+{
+ error_msg("gzip aborted\n");
+ _exit(-1);
+}
+
+static void make_crc_table()
+{
+ unsigned long table_entry; /* crc shift register */
+ unsigned long poly = 0; /* polynomial exclusive-or pattern */
+ int i; /* counter for all possible eight bit values */
+ int k; /* byte being shifted into crc apparatus */
+
+ /* terms of polynomial defining this crc (except x^32): */
+ static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* initial shift register value */
+ crc = 0xffffffffL;
+ crc_table = (unsigned long *) xmalloc(256 * sizeof(unsigned long));
+
+ /* Make exclusive-or pattern from polynomial (0xedb88320) */
+ for (i = 0; i < sizeof(p)/sizeof(int); i++)
+ poly |= 1L << (31 - p[i]);
+
+ /* Compute and print table of CRC's, five per line */
+ for (i = 0; i < 256; i++) {
+ table_entry = i;
+ /* The idea to initialize the register with the byte instead of
+ * zero was stolen from Haruhiko Okumura's ar002
+ */
+ for (k = 8; k; k--) {
+ table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1;
+ }
+ crc_table[i]=table_entry;
+ }
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+ int n;
+
+ if (outcnt == 0)
+ return;
+
+ for (n = 0; n < outcnt; n++) {
+ crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8);
+ }
+
+ if (fwrite(window, 1, outcnt, out_file) != outcnt) {
+ /*
+ * The Parent process may not be interested in all the data we have,
+ * in which case it will rudely close its end of the pipe and
+ * wait for us to exit.
+ */
+ if (errno == EPIPE)
+ _exit(EXIT_SUCCESS);
+
+ error_msg("Couldnt write");
+ _exit(EXIT_FAILURE);
+ }
+ bytes_out += (unsigned long) outcnt;
+ outcnt = 0;
+}
+
+/*
+ * Free the malloc'ed tables built by huft_build(), which makes a linked
+ * list of the tables it made, with the links in a dummy first entry of
+ * each table.
+ * t: table to free
+ */
+static int huft_free(huft_t *t)
+{
+ huft_t *p, *q;
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (huft_t *) NULL) {
+ q = (--p)->v.t;
+ free((char *) p);
+ p = q;
+ }
+ return 0;
+}
+
+/* Given a list of code lengths and a maximum table size, make a set of
+ * tables to decode that set of codes. Return zero on success, one if
+ * the given code set is incomplete (the tables are still built in this
+ * case), two if the input is invalid (all zero length codes or an
+ * oversubscribed set of lengths), and three if not enough memory.
+ *
+ * b: code lengths in bits (all assumed <= BMAX)
+ * n: number of codes (assumed <= N_MAX)
+ * s: number of simple-valued codes (0..s-1)
+ * d: list of base values for non-simple codes
+ * e: list of extra bits for non-simple codes
+ * t: result: starting table
+ * m: maximum lookup bits, returns actual
+ */
+static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s,
+ const unsigned short *d, const unsigned short *e, huft_t **t, int *m)
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX + 1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ unsigned i; /* counter, current code */
+ unsigned j; /* counter */
+ int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ unsigned *p; /* pointer into c[], b[], or v[] */
+ huft_t *q; /* points to current table */
+ huft_t r; /* table entry for structure assignment */
+ huft_t *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX + 1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+ /* Generate counts for each bit length */
+ memset ((void *)(c), 0, sizeof(c));
+ p = b;
+ i = n;
+ do {
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) { /* null input--all zero length codes */
+ *t = (huft_t *) NULL;
+ *m = 0;
+ return 0;
+ }
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned) l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned) l > i)
+ l = i;
+ *m = l;
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1;
+ xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+ /* Make a table of values in order of bit lengths */
+ p = b;
+ i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (huft_t *) NULL; /* just to keep compilers happy */
+ q = (huft_t *) NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++) {
+ a = c[k];
+ while (a--) {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l) {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) { /* try smaller tables up to z bits */
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) {
+ if (h) {
+ huft_free(u[0]);
+ }
+ return 3; /* not enough memory */
+ }
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h) {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (unsigned char) l; /* bits to dump before this table */
+ r.e = (unsigned char) (16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h - 1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (unsigned char) (k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s) {
+ r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (unsigned short) (*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ } else {
+ r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h]) {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+/*
+ * inflate (decompress) the codes in a deflated (compressed) block.
+ * Return an error code or zero if it all goes ok.
+ *
+ * tl, td: literal/length and distance decoder tables
+ * bl, bd: number of bits decoded by tl[] and td[]
+ */
+static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd)
+{
+ unsigned long e; /* table entry flag/number of extra bits */
+ unsigned long n, d; /* length and index for copy */
+ unsigned long w; /* current window position */
+ huft_t *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ unsigned long b; /* bit buffer */
+ unsigned k; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = outcnt; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) { /* do until end of block */
+ while (k < (unsigned) bl) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
+ do {
+ if (e == 99) {
+ return 1;
+ }
+ b >>= t->b;
+ k -= t->b;
+ e -= 16;
+ while (k < e) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
+ b >>= t->b;
+ k -= t->b;
+ if (e == 16) { /* then it's a literal */
+ window[w++] = (unsigned char) t->v.n;
+ if (w == WSIZE) {
+ outcnt=(w),
+ flush_window();
+ w = 0;
+ }
+ } else { /* it's an EOB or a length */
+
+ /* exit if end of block */
+ if (e == 15) {
+ break;
+ }
+
+ /* get length of block to copy */
+ while (k < e) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ n = t->v.n + ((unsigned) b & mask_bits[e]);
+ b >>= e;
+ k -= e;
+
+ /* decode distance of block to copy */
+ while (k < (unsigned) bd) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+
+ if ((e = (t = td + ((unsigned) b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ b >>= t->b;
+ k -= t->b;
+ e -= 16;
+ while (k < e) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
+ b >>= t->b;
+ k -= t->b;
+ while (k < e) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ d = w - t->v.n - ((unsigned) b & mask_bits[e]);
+ b >>= e;
+ k -= e;
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) { /* (this test assumes unsigned comparison) */
+ memcpy(window + w, window + d, e);
+ w += e;
+ d += e;
+ } else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ window[w++] = window[d++];
+ } while (--e);
+ if (w == WSIZE) {
+ outcnt=(w),
+ flush_window();
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+ /* restore the globals from the locals */
+ outcnt = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+/*
+ * decompress an inflated block
+ * e: last block flag
+ *
+ * GLOBAL VARIABLES: bb, kk,
+ */
+static int inflate_block(int *e)
+{
+ unsigned t; /* block type */
+ unsigned long b; /* bit buffer */
+ unsigned k; /* number of bits in bit buffer */
+ static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+ };
+ /* note: see note #13 above about the 258 in this list. */
+ static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
+ }; /* 99==invalid */
+ static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577
+ };
+ static unsigned short cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13
+ };
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+ /* read in last block bit */
+ while (k < 1) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ *e = (int) b & 1;
+ b >>= 1;
+ k -= 1;
+
+ /* read in block type */
+ while (k < 2) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ t = (unsigned) b & 3;
+ b >>= 2;
+ k -= 2;
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+ /* inflate that block type */
+ switch (t) {
+ case 0: /* Inflate stored */
+ {
+ unsigned long n; /* number of bytes in block */
+ unsigned long w; /* current window position */
+ unsigned long b_stored; /* bit buffer */
+ unsigned long k_stored; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ b_stored = bb; /* initialize bit buffer */
+ k_stored = bk;
+ w = outcnt; /* initialize window position */
+
+ /* go to byte boundary */
+ n = k_stored & 7;
+ b_stored >>= n;
+ k_stored -= n;
+
+ /* get the length and its complement */
+ while (k_stored < 16) {
+ b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
+ k_stored += 8;
+ }
+ n = ((unsigned) b_stored & 0xffff);
+ b_stored >>= 16;
+ k_stored -= 16;
+ while (k_stored < 16) {
+ b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
+ k_stored += 8;
+ }
+ if (n != (unsigned) ((~b_stored) & 0xffff)) {
+ return 1; /* error in compressed data */
+ }
+ b_stored >>= 16;
+ k_stored -= 16;
+
+ /* read and output the compressed data */
+ while (n--) {
+ while (k_stored < 8) {
+ b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
+ k_stored += 8;
+ }
+ window[w++] = (unsigned char) b_stored;
+ if (w == (unsigned long)WSIZE) {
+ outcnt=(w),
+ flush_window();
+ w = 0;
+ }
+ b_stored >>= 8;
+ k_stored -= 8;
+ }
+
+ /* restore the globals from the locals */
+ outcnt = w; /* restore global window pointer */
+ bb = b_stored; /* restore global bit buffer */
+ bk = k_stored;
+ return 0;
+ }
+ case 1: /* Inflate fixed
+ * decompress an inflated type 1 (fixed Huffman codes) block. We should
+ * either replace this with a custom decoder, or at least precompute the
+ * Huffman tables.
+ */
+ {
+ int i; /* temporary variable */
+ huft_t *tl; /* literal/length code table */
+ huft_t *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned int l[288]; /* length list for huft_build */
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++) {
+ l[i] = 8;
+ }
+ for (; i < 256; i++) {
+ l[i] = 9;
+ }
+ for (; i < 280; i++) {
+ l[i] = 7;
+ }
+ for (; i < 288; i++) { /* make a complete, but wrong code set */
+ l[i] = 8;
+ }
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
+ return i;
+ }
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) { /* make an incomplete code set */
+ l[i] = 5;
+ }
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) {
+ huft_free(tl);
+ return i;
+ }
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd)) {
+ huft_free(tl);
+ huft_free(td);
+ return 1;
+ }
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+ }
+ case 2: /* Inflate dynamic */
+ {
+ /* Tables for deflate from PKZIP's appnote.txt. */
+ static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+ };
+ int dbits = 6; /* bits in base distance lookup table */
+ int lbits = 9; /* bits in base literal/length lookup table */
+
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ huft_t *tl; /* literal/length code table */
+ huft_t *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+
+ unsigned ll[286 + 30]; /* literal/length and distance code lengths */
+ unsigned long b_dynamic; /* bit buffer */
+ unsigned k_dynamic; /* number of bits in bit buffer */
+
+ /* make local bit buffer */
+ b_dynamic = bb;
+ k_dynamic = bk;
+
+ /* read in table lengths */
+ while (k_dynamic < 5) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */
+ b_dynamic >>= 5;
+ k_dynamic -= 5;
+ while (k_dynamic < 5) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */
+ b_dynamic >>= 5;
+ k_dynamic -= 5;
+ while (k_dynamic < 4) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */
+ b_dynamic >>= 4;
+ k_dynamic -= 4;
+ if (nl > 286 || nd > 30) {
+ return 1; /* bad lengths */
+ }
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++) {
+ while (k_dynamic < 3) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ ll[border[j]] = (unsigned) b_dynamic & 7;
+ b_dynamic >>= 3;
+ k_dynamic -= 3;
+ }
+ for (; j < 19; j++) {
+ ll[border[j]] = 0;
+ }
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) {
+ if (i == 1) {
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned) i < n) {
+ while (k_dynamic < (unsigned) bl) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ j = (td = tl + ((unsigned) b_dynamic & m))->b;
+ b_dynamic >>= j;
+ k_dynamic -= j;
+ j = td->v.n;
+ if (j < 16) { /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ }
+ else if (j == 16) { /* repeat last length 3 to 6 times */
+ while (k_dynamic < 2) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ j = 3 + ((unsigned) b_dynamic & 3);
+ b_dynamic >>= 2;
+ k_dynamic -= 2;
+ if ((unsigned) i + j > n) {
+ return 1;
+ }
+ while (j--) {
+ ll[i++] = l;
+ }
+ } else if (j == 17) { /* 3 to 10 zero length codes */
+ while (k_dynamic < 3) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ j = 3 + ((unsigned) b_dynamic & 7);
+ b_dynamic >>= 3;
+ k_dynamic -= 3;
+ if ((unsigned) i + j > n) {
+ return 1;
+ }
+ while (j--) {
+ ll[i++] = 0;
+ }
+ l = 0;
+ } else { /* j == 18: 11 to 138 zero length codes */
+ while (k_dynamic < 7) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ j = 11 + ((unsigned) b_dynamic & 0x7f);
+ b_dynamic >>= 7;
+ k_dynamic -= 7;
+ if ((unsigned) i + j > n) {
+ return 1;
+ }
+ while (j--) {
+ ll[i++] = 0;
+ }
+ l = 0;
+ }
+ }
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+ /* restore the global bit buffer */
+ bb = b_dynamic;
+ bk = k_dynamic;
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) {
+ if (i == 1) {
+ error_msg("Incomplete literal tree");
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) {
+ if (i == 1) {
+ error_msg("incomplete distance tree");
+ huft_free(td);
+ }
+ huft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd)) {
+ huft_free(tl);
+ huft_free(td);
+ return 1;
+ }
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+ }
+ default:
+ /* bad block type */
+ return 2;
+ }
+}
+
+/*
+ * decompress an inflated entry
+ *
+ * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
+ */
+static int inflate()
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h = 0; /* maximum struct huft's malloc'ed */
+
+ /* initialize window, bit buffer */
+ outcnt = 0;
+ bk = 0;
+ bb = 0;
+
+ /* decompress until the last block */
+ do {
+ hufts = 0;
+ if ((r = inflate_block(&e)) != 0) {
+ return r;
+ }
+ if (hufts > h) {
+ h = hufts;
+ }
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte. */
+ while (bk >= 8) {
+ bk -= 8;
+ ungetc((bb << bk), in_file);
+ }
+
+ /* flush out window */
+ flush_window();
+
+ /* return success */
+ return 0;
+}
+
+/* ===========================================================================
+ * Unzip in to out. This routine works on both gzip and pkzip files.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets inptr to insize-1 included.
+ * The magic header has already been checked. The output buffer is cleared.
+ * in, out: input and output file descriptors
+ */
+extern int unzip(FILE *l_in_file, FILE *l_out_file)
+{
+ const int extra_field = 0x04; /* bit 2 set: extra field present */
+ const int orig_name = 0x08; /* bit 3 set: original file name present */
+ const int comment = 0x10; /* bit 4 set: file comment present */
+ unsigned char buf[8]; /* extended local header */
+ unsigned char flags; /* compression flags */
+ char magic[2]; /* magic header */
+ int method;
+ typedef void (*sig_type) (int);
+ int exit_code=0; /* program exit code */
+ int i;
+
+ in_file = l_in_file;
+ out_file = l_out_file;
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGINT, (sig_type) abort_gzip);
+ }
+#ifdef SIGTERM
+// if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+// (void) signal(SIGTERM, (sig_type) abort_gzip);
+// }
+#endif
+#ifdef SIGHUP
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGHUP, (sig_type) abort_gzip);
+ }
+#endif
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /* Allocate all global buffers (for DYN_ALLOC option) */
+ window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
+ outcnt = 0;
+ bytes_out = 0L;
+
+ magic[0] = fgetc(in_file);
+ magic[1] = fgetc(in_file);
+
+ /* Magic header for gzip files, 1F 8B = \037\213 */
+ if (memcmp(magic, "\037\213", 2) != 0) {
+ error_msg("Invalid gzip magic");
+ return EXIT_FAILURE;
+ }
+
+ method = (int) fgetc(in_file);
+ if (method != 8) {
+ error_msg("unknown method %d -- get newer version of gzip", method);
+ exit_code = 1;
+ return -1;
+ }
+
+ flags = (unsigned char) fgetc(in_file);
+
+ /* Ignore time stamp(4), extra flags(1), OS type(1) */
+ for (i = 0; i < 6; i++)
+ fgetc(in_file);
+
+ if ((flags & extra_field) != 0) {
+ size_t extra;
+ extra = fgetc(in_file);
+ extra += fgetc(in_file) << 8;
+
+ for (i = 0; i < extra; i++)
+ fgetc(in_file);
+ }
+
+ /* Discard original name if any */
+ if ((flags & orig_name) != 0) {
+ while (fgetc(in_file) != 0); /* null */
+ }
+
+ /* Discard file comment if any */
+ if ((flags & comment) != 0) {
+ while (fgetc(in_file) != 0); /* null */
+ }
+
+ if (method < 0) {
+ return(exit_code);
+ }
+
+ make_crc_table();
+
+ /* Decompress */
+ if (method == 8) {
+
+ int res = inflate();
+
+ if (res == 3) {
+ perror_msg("inflate");
+ exit_code = 1;
+ } else if (res != 0) {
+ error_msg("invalid compressed data--format violated");
+ exit_code = 1;
+ }
+
+ } else {
+ error_msg("internal error, invalid method");
+ exit_code = 1;
+ }
+
+ /* Get the crc and original length
+ * crc32 (see algorithm.doc)
+ * uncompressed input size modulo 2^32
+ */
+ fread(buf, 1, 8, in_file);
+
+ /* Validate decompression - crc */
+ if (!exit_code && (unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
+ error_msg("invalid compressed data--crc error");
+ exit_code = 1;
+ }
+ /* Validate decompression - size */
+ if (!exit_code && ((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) {
+ error_msg("invalid compressed data--length error");
+ exit_code = 1;
+ }
+
+ free(window);
+ free(crc_table);
+
+ window = NULL;
+ crc_table = NULL;
+
+ return exit_code;
+}
diff --git a/src/libbb/.svn/text-base/wfopen.c.svn-base b/src/libbb/.svn/text-base/wfopen.c.svn-base
new file mode 100644
index 0000000..f58ec90
--- /dev/null
+++ b/src/libbb/.svn/text-base/wfopen.c.svn-base
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "libbb.h"
+
+FILE *wfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL) {
+ perror_msg("%s", path);
+ errno = 0;
+ }
+ return fp;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/.svn/text-base/xfuncs.c.svn-base b/src/libbb/.svn/text-base/xfuncs.c.svn-base
new file mode 100644
index 0000000..f577315
--- /dev/null
+++ b/src/libbb/.svn/text-base/xfuncs.c.svn-base
@@ -0,0 +1,93 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libbb.h"
+
+
+extern void *xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (ptr == NULL && size != 0)
+ perror_msg_and_die("malloc");
+ return ptr;
+}
+
+extern void *xrealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL && size != 0)
+ perror_msg_and_die("realloc");
+ return ptr;
+}
+
+extern void *xcalloc(size_t nmemb, size_t size)
+{
+ void *ptr = calloc(nmemb, size);
+ if (ptr == NULL && nmemb != 0 && size != 0)
+ perror_msg_and_die("calloc");
+ return ptr;
+}
+
+extern char * xstrdup (const char *s) {
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+
+ t = strdup (s);
+
+ if (t == NULL)
+ perror_msg_and_die("strdup");
+
+ return t;
+}
+
+extern char * xstrndup (const char *s, int n) {
+ char *t;
+
+ if (s == NULL)
+ error_msg_and_die("xstrndup bug");
+
+ t = xmalloc(++n);
+
+ return safe_strncpy(t,s,n);
+}
+
+FILE *xfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL)
+ perror_msg_and_die("%s", path);
+ return fp;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/.svn/text-base/xreadlink.c.svn-base b/src/libbb/.svn/text-base/xreadlink.c.svn-base
new file mode 100644
index 0000000..7d77a3b
--- /dev/null
+++ b/src/libbb/.svn/text-base/xreadlink.c.svn-base
@@ -0,0 +1,37 @@
+/*
+ * xreadlink.c - safe implementation of readlink.
+ * Returns a NULL on failure...
+ */
+
+#include <stdio.h>
+
+/*
+ * NOTE: This function returns a malloced char* that you will have to free
+ * yourself. You have been warned.
+ */
+
+#include <unistd.h>
+#include "libbb.h"
+
+extern char *xreadlink(const char *path)
+{
+ static const int GROWBY = 80; /* how large we will grow strings by */
+
+ char *buf = NULL;
+ int bufsize = 0, readsize = 0;
+
+ do {
+ buf = xrealloc(buf, bufsize += GROWBY);
+ readsize = readlink(path, buf, bufsize); /* 1st try */
+ if (readsize == -1) {
+ perror_msg("%s", path);
+ return NULL;
+ }
+ }
+ while (bufsize < readsize + 1);
+
+ buf[readsize] = '\0';
+
+ return buf;
+}
+
diff --git a/src/libbb/Makefile.am b/src/libbb/Makefile.am
new file mode 100644
index 0000000..1cc82df
--- /dev/null
+++ b/src/libbb/Makefile.am
@@ -0,0 +1,26 @@
+HOST_CPU=@host_cpu@
+BUILD_CPU=@build_cpu@
+ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@
+
+noinst_LTLIBRARIES = libbb.la
+
+libbb_la_SOURCES = gz_open.c \
+ libbb.h \
+ unzip.c \
+ wfopen.c \
+ unarchive.c \
+ copy_file.c \
+ copy_file_chunk.c \
+ xreadlink.c \
+ concat_path_file.c \
+ xfuncs.c \
+ last_char_is.c \
+ make_directory.c \
+ safe_strncpy.c \
+ parse_mode.c \
+ time_string.c \
+ all_read.c \
+ mode_string.c
+
+libbb_la_CFLAGS = $(ALL_CFLAGS)
+#libbb_la_LDFLAGS = -static
diff --git a/src/libbb/all_read.c b/src/libbb/all_read.c
new file mode 100644
index 0000000..6ec731a
--- /dev/null
+++ b/src/libbb/all_read.c
@@ -0,0 +1,83 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libbb.h"
+
+extern void archive_xread_all(int fd , char *buf, size_t count)
+{
+ ssize_t size;
+
+ size = full_read(fd, buf, count);
+ if (size != count) {
+ perror_msg_and_die("Short read");
+ }
+ return;
+}
+
+/*
+ * Read all of the supplied buffer from a file.
+ * This does multiple reads as necessary.
+ * Returns the amount read, or -1 on an error.
+ * A short read is returned on an end of file.
+ */
+ssize_t full_read(int fd, char *buf, int len)
+{
+ ssize_t cc;
+ ssize_t total;
+
+ total = 0;
+
+ while (len > 0) {
+ cc = safe_read(fd, buf, len);
+
+ if (cc < 0)
+ return cc; /* read() returns -1 on failure. */
+
+ if (cc == 0)
+ break;
+
+ buf = ((char *)buf) + cc;
+ total += cc;
+ len -= cc;
+ }
+
+ return total;
+}
+
+
+ssize_t safe_read(int fd, void *buf, size_t count)
+{
+ ssize_t n;
+
+ do {
+ n = read(fd, buf, count);
+ } while (n < 0 && errno == EINTR);
+
+ return n;
+}
+
+
+
+/* END CODE */
+
diff --git a/src/libbb/concat_path_file.c b/src/libbb/concat_path_file.c
new file mode 100644
index 0000000..e62b99e
--- /dev/null
+++ b/src/libbb/concat_path_file.c
@@ -0,0 +1,45 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/* concatenate path and file name to new allocation buffer,
+ * not addition '/' if path name already have '/'
+*/
+
+#include <string.h>
+#include "libbb.h"
+
+extern char *concat_path_file(const char *path, const char *filename)
+{
+ char *outbuf;
+ char *lc;
+
+ if (!path)
+ path="";
+ lc = last_char_is(path, '/');
+ while (*filename == '/')
+ filename++;
+ outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL));
+ sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename);
+
+ return outbuf;
+}
diff --git a/src/libbb/copy_file.c b/src/libbb/copy_file.c
new file mode 100644
index 0000000..fb76669
--- /dev/null
+++ b/src/libbb/copy_file.c
@@ -0,0 +1,231 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini copy_file implementation for busybox
+ *
+ *
+ * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libbb.h"
+
+int copy_file(const char *source, const char *dest, int flags)
+{
+ struct stat source_stat;
+ struct stat dest_stat;
+ int dest_exists = 1;
+ int status = 0;
+
+ if (((flags & FILEUTILS_PRESERVE_SYMLINKS) &&
+ lstat(source, &source_stat) < 0) ||
+ (!(flags & FILEUTILS_PRESERVE_SYMLINKS) &&
+ stat(source, &source_stat) < 0)) {
+ perror_msg("%s", source);
+ return -1;
+ }
+
+ if (stat(dest, &dest_stat) < 0) {
+ if (errno != ENOENT) {
+ perror_msg("unable to stat `%s'", dest);
+ return -1;
+ }
+ dest_exists = 0;
+ }
+
+ if (dest_exists && source_stat.st_rdev == dest_stat.st_rdev &&
+ source_stat.st_ino == dest_stat.st_ino) {
+ error_msg("`%s' and `%s' are the same file", source, dest);
+ return -1;
+ }
+
+ if (S_ISDIR(source_stat.st_mode)) {
+ DIR *dp;
+ struct dirent *d;
+ mode_t saved_umask = 0;
+
+ if (!(flags & FILEUTILS_RECUR)) {
+ error_msg("%s: omitting directory", source);
+ return -1;
+ }
+
+ /* Create DEST. */
+ if (dest_exists) {
+ if (!S_ISDIR(dest_stat.st_mode)) {
+ error_msg("`%s' is not a directory", dest);
+ return -1;
+ }
+ } else {
+ mode_t mode;
+ saved_umask = umask(0);
+
+ mode = source_stat.st_mode;
+ if (!(flags & FILEUTILS_PRESERVE_STATUS))
+ mode = source_stat.st_mode & ~saved_umask;
+ mode |= S_IRWXU;
+
+ if (mkdir(dest, mode) < 0) {
+ umask(saved_umask);
+ perror_msg("cannot create directory `%s'", dest);
+ return -1;
+ }
+
+ umask(saved_umask);
+ }
+
+ /* Recursively copy files in SOURCE. */
+ if ((dp = opendir(source)) == NULL) {
+ perror_msg("unable to open directory `%s'", source);
+ status = -1;
+ goto end;
+ }
+
+ while ((d = readdir(dp)) != NULL) {
+ char *new_source, *new_dest;
+
+ if (strcmp(d->d_name, ".") == 0 ||
+ strcmp(d->d_name, "..") == 0)
+ continue;
+
+ new_source = concat_path_file(source, d->d_name);
+ new_dest = concat_path_file(dest, d->d_name);
+ if (copy_file(new_source, new_dest, flags) < 0)
+ status = -1;
+ free(new_source);
+ free(new_dest);
+ }
+
+ /* ??? What if an error occurs in readdir? */
+
+ if (closedir(dp) < 0) {
+ perror_msg("unable to close directory `%s'", source);
+ status = -1;
+ }
+
+ if (!dest_exists &&
+ chmod(dest, source_stat.st_mode & ~saved_umask) < 0) {
+ perror_msg("unable to change permissions of `%s'", dest);
+ status = -1;
+ }
+ } else if (S_ISREG(source_stat.st_mode)) {
+ FILE *sfp, *dfp;
+
+ if (dest_exists) {
+ if ((dfp = fopen(dest, "w")) == NULL) {
+ if (!(flags & FILEUTILS_FORCE)) {
+ perror_msg("unable to open `%s'", dest);
+ return -1;
+ }
+
+ if (unlink(dest) < 0) {
+ perror_msg("unable to remove `%s'", dest);
+ return -1;
+ }
+
+ dest_exists = 0;
+ }
+ }
+
+ if (!dest_exists) {
+ int fd;
+
+ if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 ||
+ (dfp = fdopen(fd, "w")) == NULL) {
+ if (fd >= 0)
+ close(fd);
+ perror_msg("unable to open `%s'", dest);
+ return -1;
+ }
+ }
+
+ if ((sfp = fopen(source, "r")) == NULL) {
+ fclose(dfp);
+ perror_msg("unable to open `%s'", source);
+ status = -1;
+ goto end;
+ }
+
+ if (copy_file_chunk(sfp, dfp, -1) < 0)
+ status = -1;
+
+ if (fclose(dfp) < 0) {
+ perror_msg("unable to close `%s'", dest);
+ status = -1;
+ }
+
+ if (fclose(sfp) < 0) {
+ perror_msg("unable to close `%s'", source);
+ status = -1;
+ }
+ } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
+ S_ISSOCK(source_stat.st_mode)) {
+ if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
+ perror_msg("unable to create `%s'", dest);
+ return -1;
+ }
+ } else if (S_ISFIFO(source_stat.st_mode)) {
+ if (mkfifo(dest, source_stat.st_mode) < 0) {
+ perror_msg("cannot create fifo `%s'", dest);
+ return -1;
+ }
+ } else if (S_ISLNK(source_stat.st_mode)) {
+ char *lpath = xreadlink(source);
+ if (symlink(lpath, dest) < 0) {
+ perror_msg("cannot create symlink `%s'", dest);
+ return -1;
+ }
+ free(lpath);
+
+#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
+ if (flags & FILEUTILS_PRESERVE_STATUS)
+ if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
+ perror_msg("unable to preserve ownership of `%s'", dest);
+#endif
+ return 0;
+ } else {
+ error_msg("internal error: unrecognized file type");
+ return -1;
+ }
+
+end:
+
+ if (flags & FILEUTILS_PRESERVE_STATUS) {
+ struct utimbuf times;
+
+ times.actime = source_stat.st_atime;
+ times.modtime = source_stat.st_mtime;
+ if (utime(dest, &times) < 0)
+ perror_msg("unable to preserve times of `%s'", dest);
+ if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
+ source_stat.st_mode &= ~(S_ISUID | S_ISGID);
+ perror_msg("unable to preserve ownership of `%s'", dest);
+ }
+ if (chmod(dest, source_stat.st_mode) < 0)
+ perror_msg("unable to preserve permissions of `%s'", dest);
+ }
+
+ return status;
+}
diff --git a/src/libbb/copy_file_chunk.c b/src/libbb/copy_file_chunk.c
new file mode 100644
index 0000000..63d2ab1
--- /dev/null
+++ b/src/libbb/copy_file_chunk.c
@@ -0,0 +1,70 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include "libbb.h"
+
+/* Copy CHUNKSIZE bytes (or until EOF if CHUNKSIZE equals -1) from SRC_FILE
+ * to DST_FILE. */
+extern int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize)
+{
+ size_t nread, nwritten, size;
+ char buffer[BUFSIZ];
+
+ while (chunksize != 0) {
+ if (chunksize > BUFSIZ)
+ size = BUFSIZ;
+ else
+ size = chunksize;
+
+ nread = fread (buffer, 1, size, src_file);
+
+ if (nread != size && ferror (src_file)) {
+ perror_msg ("read");
+ return -1;
+ } else if (nread == 0) {
+ if (chunksize != -1) {
+ error_msg ("Unable to read all data");
+ return -1;
+ }
+
+ return 0;
+ }
+
+ nwritten = fwrite (buffer, 1, nread, dst_file);
+
+ if (nwritten != nread) {
+ if (ferror (dst_file))
+ perror_msg ("write");
+ else
+ error_msg ("Unable to write all data");
+ return -1;
+ }
+
+ if (chunksize != -1)
+ chunksize -= nwritten;
+ }
+
+ return 0;
+}
diff --git a/src/libbb/gz_open.c b/src/libbb/gz_open.c
new file mode 100644
index 0000000..bdc7564
--- /dev/null
+++ b/src/libbb/gz_open.c
@@ -0,0 +1,149 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "libbb.h"
+
+static int gz_use_vfork;
+
+FILE *
+gz_open(FILE *compressed_file, int *pid)
+{
+ int unzip_pipe[2];
+ off_t floc;
+ int cfile = -1;
+
+ gz_use_vfork = (getenv("OPKG_USE_VFORK") != NULL);
+
+ if (gz_use_vfork) {
+ /* Create a new file descriptor for the input stream
+ * (it *must* be associated with a file), and lseek()
+ * to the same position in that fd as the stream.
+ */
+ cfile = dup(fileno(compressed_file));
+ floc = ftello(compressed_file);
+ lseek(cfile, floc, SEEK_SET);
+ setenv("GZIP", "--quiet", 0);
+ }
+
+ if (pipe(unzip_pipe)!=0) {
+ perror_msg("pipe");
+ return(NULL);
+ }
+
+ /* If we don't flush, we end up with two copies of anything pending,
+ one from the parent, one from the child */
+ fflush(stdout);
+ fflush(stderr);
+
+ if (gz_use_vfork) {
+ *pid = vfork();
+ } else {
+ *pid = fork();
+ }
+
+ if (*pid<0) {
+ perror_msg("fork");
+ return(NULL);
+ }
+
+ if (*pid==0) {
+ /* child process */
+ close(unzip_pipe[0]);
+ if (gz_use_vfork) {
+ dup2(unzip_pipe[1], 1);
+ dup2(cfile, 0);
+ execlp("gunzip","gunzip",NULL);
+ /* If we get here, we had a failure */
+ _exit(EXIT_FAILURE);
+ } else {
+ unzip(compressed_file, fdopen(unzip_pipe[1], "w"));
+ fflush(NULL);
+ fclose(compressed_file);
+ close(unzip_pipe[1]);
+ _exit(EXIT_SUCCESS);
+ }
+ }
+ /* Parent process is executing here */
+ if (gz_use_vfork) {
+ close(cfile);
+ }
+ close(unzip_pipe[1]);
+ return(fdopen(unzip_pipe[0], "r"));
+}
+
+int
+gz_close(int gunzip_pid)
+{
+ int status;
+ int ret;
+
+ if (gz_use_vfork) {
+ /* The gunzip process remains running in the background if we
+ * used the vfork()/exec() technique - so we have to kill it
+ * forcibly. There might be a better way to do this, but that
+ * affect a lot of other parts of opkg, and this works fine.
+ */
+ if (kill(gunzip_pid, SIGTERM) == -1) {
+ perror_msg("gz_close(): unable to kill gunzip pid.");
+ return -1;
+ }
+ }
+
+
+ if (waitpid(gunzip_pid, &status, 0) == -1) {
+ perror_msg("waitpid");
+ return -1;
+ }
+
+ if (gz_use_vfork) {
+ /* Bail out here if we used the vfork()/exec() technique. */
+ return 0;
+ }
+
+ if (WIFSIGNALED(status)) {
+ error_msg("Unzip process killed by signal %d.\n",
+ WTERMSIG(status));
+ return -1;
+ }
+
+ if (!WIFEXITED(status)) {
+ /* shouldn't happen */
+ error_msg("Your system is broken: got status %d from waitpid.\n",
+ status);
+ return -1;
+ }
+
+ if ((ret = WEXITSTATUS(status))) {
+ error_msg("Unzip process failed with return code %d.\n",
+ ret);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/libbb/last_char_is.c b/src/libbb/last_char_is.c
new file mode 100644
index 0000000..26c2423
--- /dev/null
+++ b/src/libbb/last_char_is.c
@@ -0,0 +1,40 @@
+/*
+ * busybox library eXtended function
+ *
+ * Copyright (C) 2001 Larry Doolittle, <ldoolitt@recycle.lbl.gov>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <string.h>
+#include "libbb.h"
+
+/* Find out if the last character of a string matches the one given Don't
+ * underrun the buffer if the string length is 0. Also avoids a possible
+ * space-hogging inline of strlen() per usage.
+ */
+char * last_char_is(const char *s, int c)
+{
+ char *sret;
+ if (!s)
+ return NULL;
+ sret = (char *)s+strlen(s)-1;
+ if (sret>=s && *sret == c) {
+ return sret;
+ } else {
+ return NULL;
+ }
+}
diff --git a/src/libbb/libbb.h b/src/libbb/libbb.h
new file mode 100644
index 0000000..4e1fafc
--- /dev/null
+++ b/src/libbb/libbb.h
@@ -0,0 +1,123 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Busybox main internal header file
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __LIBBB_H__
+#define __LIBBB_H__ 1
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <netdb.h>
+
+#include "../libopkg/opkg_message.h"
+
+#ifndef FALSE
+#define FALSE ((int) 0)
+#endif
+
+#ifndef TRUE
+#define TRUE ((int) 1)
+#endif
+
+#define error_msg(fmt, args...) opkg_msg(ERROR, fmt"\n", ##args)
+#define perror_msg(fmt, args...) opkg_perror(ERROR, fmt, ##args)
+#define error_msg_and_die(fmt, args...) \
+ do { \
+ error_msg(fmt, ##args); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+#define perror_msg_and_die(fmt, args...) \
+ do { \
+ perror_msg(fmt, ##args); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+
+extern void archive_xread_all(int fd, char *buf, size_t count);
+
+const char *mode_string(int mode);
+const char *time_string(time_t timeVal);
+
+int copy_file(const char *source, const char *dest, int flags);
+int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize);
+ssize_t safe_read(int fd, void *buf, size_t count);
+ssize_t full_read(int fd, char *buf, int len);
+
+extern int parse_mode( const char* s, mode_t* theMode);
+
+extern FILE *wfopen(const char *path, const char *mode);
+extern FILE *xfopen(const char *path, const char *mode);
+
+extern void *xmalloc (size_t size);
+extern void *xrealloc(void *old, size_t size);
+extern void *xcalloc(size_t nmemb, size_t size);
+extern char *xstrdup (const char *s);
+extern char *xstrndup (const char *s, int n);
+extern char *safe_strncpy(char *dst, const char *src, size_t size);
+
+char *xreadlink(const char *path);
+char *concat_path_file(const char *path, const char *filename);
+char *last_char_is(const char *s, int c);
+
+typedef struct file_headers_s {
+ char *name;
+ char *link_name;
+ off_t size;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+ time_t mtime;
+ dev_t device;
+} file_header_t;
+
+enum extract_functions_e {
+ extract_verbose_list = 1,
+ extract_list = 2,
+ extract_one_to_buffer = 4,
+ extract_to_stream = 8,
+ extract_all_to_fs = 16,
+ extract_preserve_date = 32,
+ extract_data_tar_gz = 64,
+ extract_control_tar_gz = 128,
+ extract_unzip_only = 256,
+ extract_unconditional = 512,
+ extract_create_leading_dirs = 1024,
+ extract_quiet = 2048,
+ extract_exclude_list = 4096
+};
+
+char *deb_extract(const char *package_filename, FILE *out_stream,
+ const int extract_function, const char *prefix,
+ const char *filename, int *err);
+
+extern int unzip(FILE *l_in_file, FILE *l_out_file);
+extern int gz_close(int gunzip_pid);
+extern FILE *gz_open(FILE *compressed_file, int *pid);
+
+int make_directory (const char *path, long mode, int flags);
+
+enum {
+ FILEUTILS_PRESERVE_STATUS = 1,
+ FILEUTILS_PRESERVE_SYMLINKS = 2,
+ FILEUTILS_RECUR = 4,
+ FILEUTILS_FORCE = 8,
+};
+
+#endif /* __LIBBB_H__ */
diff --git a/src/libbb/make_directory.c b/src/libbb/make_directory.c
new file mode 100644
index 0000000..86ab554
--- /dev/null
+++ b/src/libbb/make_directory.c
@@ -0,0 +1,80 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini make_directory implementation for busybox
+ *
+ * Copyright (C) 2001 Matt Kraai.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libgen.h>
+
+#include "libbb.h"
+
+/* Create the directory PATH with mode MODE, or the default if MODE is -1.
+ * Also create parent directories as necessary if flags contains
+ * FILEUTILS_RECUR. */
+
+int make_directory (const char *path, long mode, int flags)
+{
+ if (!(flags & FILEUTILS_RECUR)) {
+ if (mkdir (path, 0777) < 0) {
+ perror_msg ("Cannot create directory `%s'", path);
+ return -1;
+ }
+
+ if (mode != -1 && chmod (path, mode) < 0) {
+ perror_msg ("Cannot set permissions of directory `%s'", path);
+ return -1;
+ }
+ } else {
+ struct stat st;
+
+ if (stat (path, &st) < 0 && errno == ENOENT) {
+ int status;
+ char *pathcopy, *parent, *parentcopy;
+ mode_t mask;
+
+ mask = umask (0);
+ umask (mask);
+
+ /* dirname is unsafe, it may both modify the
+ memory of the path argument and may return
+ a pointer to static memory, which can then
+ be modified by consequtive calls to dirname */
+
+ pathcopy = xstrdup (path);
+ parent = dirname (pathcopy);
+ parentcopy = xstrdup (parent);
+ status = make_directory (parentcopy, (0777 & ~mask)
+ | 0300, FILEUTILS_RECUR);
+ free (pathcopy);
+ free (parentcopy);
+
+
+ if (status < 0 || make_directory (path, mode, 0) < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/libbb/mode_string.c b/src/libbb/mode_string.c
new file mode 100644
index 0000000..12dc179
--- /dev/null
+++ b/src/libbb/mode_string.c
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include "libbb.h"
+
+
+
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+
+/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
+static const mode_t SBIT[] = {
+ 0, 0, S_ISUID,
+ 0, 0, S_ISGID,
+ 0, 0, S_ISVTX
+};
+
+/* The 9 mode bits to test */
+static const mode_t MBIT[] = {
+ S_IRUSR, S_IWUSR, S_IXUSR,
+ S_IRGRP, S_IWGRP, S_IXGRP,
+ S_IROTH, S_IWOTH, S_IXOTH
+};
+
+static const char MODE1[] = "rwxrwxrwx";
+static const char MODE0[] = "---------";
+static const char SMODE1[] = "..s..s..t";
+static const char SMODE0[] = "..S..S..T";
+
+/*
+ * Return the standard ls-like mode string from a file mode.
+ * This is static and so is overwritten on each call.
+ */
+const char *mode_string(int mode)
+{
+ static char buf[12];
+
+ int i;
+
+ buf[0] = TYPECHAR(mode);
+ for (i = 0; i < 9; i++) {
+ if (mode & SBIT[i])
+ buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
+ else
+ buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
+ }
+ return buf;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/parse_mode.c b/src/libbb/parse_mode.c
new file mode 100644
index 0000000..02668c7
--- /dev/null
+++ b/src/libbb/parse_mode.c
@@ -0,0 +1,134 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) many different people. If you wrote this, please
+ * acknowledge your work.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "libbb.h"
+
+
+/* This function parses the sort of string you might pass
+ * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the
+ * correct mode described by the string. */
+extern int parse_mode(const char *s, mode_t * theMode)
+{
+ static const mode_t group_set[] = {
+ S_ISUID | S_IRWXU, /* u */
+ S_ISGID | S_IRWXG, /* g */
+ S_IRWXO, /* o */
+ S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */
+ };
+
+ static const mode_t mode_set[] = {
+ S_IRUSR | S_IRGRP | S_IROTH, /* r */
+ S_IWUSR | S_IWGRP | S_IWOTH, /* w */
+ S_IXUSR | S_IXGRP | S_IXOTH, /* x */
+ S_ISUID | S_ISGID, /* s */
+ S_ISVTX /* t */
+ };
+
+ static const char group_chars[] = "ugoa";
+ static const char mode_chars[] = "rwxst";
+
+ const char *p;
+
+ mode_t andMode =
+ S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+ mode_t orMode = 0;
+ mode_t mode;
+ mode_t groups;
+ char type;
+ char c;
+
+ if (s==NULL) {
+ return (FALSE);
+ }
+
+ do {
+ mode = 0;
+ groups = 0;
+ NEXT_GROUP:
+ if ((c = *s++) == '\0') {
+ return -1;
+ }
+ for (p=group_chars ; *p ; p++) {
+ if (*p == c) {
+ groups |= group_set[(int)(p-group_chars)];
+ goto NEXT_GROUP;
+ }
+ }
+ switch (c) {
+ case '=':
+ case '+':
+ case '-':
+ type = c;
+ if (groups == 0) { /* The default is "all" */
+ groups |= S_ISUID | S_ISGID | S_ISVTX
+ | S_IRWXU | S_IRWXG | S_IRWXO;
+ }
+ break;
+ default:
+ if ((c < '0') || (c > '7') || (mode | groups)) {
+ return (FALSE);
+ } else {
+ *theMode = strtol(--s, NULL, 8);
+ return (TRUE);
+ }
+ }
+
+ NEXT_MODE:
+ if (((c = *s++) != '\0') && (c != ',')) {
+ for (p=mode_chars ; *p ; p++) {
+ if (*p == c) {
+ mode |= mode_set[(int)(p-mode_chars)];
+ goto NEXT_MODE;
+ }
+ }
+ break; /* We're done so break out of loop.*/
+ }
+ switch (type) {
+ case '=':
+ andMode &= ~(groups); /* Now fall through. */
+ case '+':
+ orMode |= mode & groups;
+ break;
+ case '-':
+ andMode &= ~(mode & groups);
+ orMode &= ~(mode & groups);
+ break;
+ }
+ } while (c == ',');
+
+ *theMode &= andMode;
+ *theMode |= orMode;
+
+ return TRUE;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/safe_strncpy.c b/src/libbb/safe_strncpy.c
new file mode 100644
index 0000000..eb2dbab
--- /dev/null
+++ b/src/libbb/safe_strncpy.c
@@ -0,0 +1,42 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include "libbb.h"
+
+
+
+/* Like strncpy but make sure the resulting string is always 0 terminated. */
+extern char * safe_strncpy(char *dst, const char *src, size_t size)
+{
+ dst[size-1] = '\0';
+ return strncpy(dst, src, size-1);
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/time_string.c b/src/libbb/time_string.c
new file mode 100644
index 0000000..d103a02
--- /dev/null
+++ b/src/libbb/time_string.c
@@ -0,0 +1,62 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <utime.h>
+#include "libbb.h"
+
+
+/*
+ * Return the standard ls-like time string from a time_t
+ * This is static and so is overwritten on each call.
+ */
+const char *time_string(time_t timeVal)
+{
+ time_t now;
+ char *str;
+ static char buf[26];
+
+ time(&now);
+
+ str = ctime(&timeVal);
+
+ strcpy(buf, &str[4]);
+ buf[12] = '\0';
+
+ if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
+ strcpy(&buf[7], &str[20]);
+ buf[11] = '\0';
+ }
+
+ return buf;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/unarchive.c b/src/libbb/unarchive.c
new file mode 100644
index 0000000..5d4464f
--- /dev/null
+++ b/src/libbb/unarchive.c
@@ -0,0 +1,784 @@
+/*
+ * Copyright (C) 2000 by Glenn McGrath
+ * Copyright (C) 2001 by Laurence Anderson
+ *
+ * Based on previous work by busybox developers and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <libgen.h>
+
+#include "libbb.h"
+
+#define CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY 1
+#define CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+
+#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+static char *longname = NULL;
+static char *linkname = NULL;
+#endif
+
+off_t archive_offset;
+
+#define SEEK_BUF 4096
+static ssize_t
+seek_by_read(FILE* fd, size_t len)
+{
+ ssize_t cc, total = 0;
+ char buf[SEEK_BUF];
+
+ while (len) {
+ cc = fread(buf, sizeof(buf[0]),
+ len > SEEK_BUF ? SEEK_BUF : len,
+ fd);
+
+ total += cc;
+ len -= cc;
+
+ if(feof(fd) || ferror(fd))
+ break;
+ }
+ return total;
+}
+
+static void
+seek_sub_file(FILE *fd, const int count)
+{
+ archive_offset += count;
+
+ /* Do not use fseek() on a pipe. It may fail with ESPIPE, leaving the
+ * stream at an undefined location.
+ */
+ seek_by_read(fd, count);
+
+ return;
+}
+
+
+/* Extract the data postioned at src_stream to either filesystem, stdout or
+ * buffer depending on the value of 'function' which is defined in libbb.h
+ *
+ * prefix doesnt have to be just a directory, it may prefix the filename as well.
+ *
+ * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath
+ * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have
+ * 'dpkg.' as their prefix
+ *
+ * For this reason if prefix does point to a dir then it must end with a
+ * trailing '/' or else the last dir will be assumed to be the file prefix
+ */
+static char *
+extract_archive(FILE *src_stream, FILE *out_stream,
+ const file_header_t *file_entry, const int function,
+ const char *prefix,
+ int *err)
+{
+ FILE *dst_stream = NULL;
+ char *full_name = NULL;
+ char *full_link_name = NULL;
+ char *buffer = NULL;
+ struct utimbuf t;
+
+ *err = 0;
+
+ /* prefix doesnt have to be a proper path it may prepend
+ * the filename as well */
+ if (prefix != NULL) {
+ /* strip leading '/' in filename to extract as prefix may not be dir */
+ /* Cant use concat_path_file here as prefix might not be a directory */
+ char *path = file_entry->name;
+ if (strncmp("./", path, 2) == 0) {
+ path += 2;
+ if (strlen(path) == 0)
+ /* Do nothing, current dir already exists. */
+ return NULL;
+ }
+ full_name = xmalloc(strlen(prefix) + strlen(path) + 1);
+ strcpy(full_name, prefix);
+ strcat(full_name, path);
+ if ( file_entry->link_name ){
+ full_link_name = xmalloc(strlen(prefix) + strlen(file_entry->link_name) + 1);
+ strcpy(full_link_name, prefix);
+ strcat(full_link_name, file_entry->link_name);
+ }
+ } else {
+ full_name = xstrdup(file_entry->name);
+ if ( file_entry->link_name )
+ full_link_name = xstrdup(file_entry->link_name);
+ }
+
+
+ if (function & extract_to_stream) {
+ if (S_ISREG(file_entry->mode)) {
+ *err = copy_file_chunk(src_stream, out_stream, file_entry->size);
+ archive_offset += file_entry->size;
+ }
+ }
+ else if (function & extract_one_to_buffer) {
+ if (S_ISREG(file_entry->mode)) {
+ buffer = (char *) xmalloc(file_entry->size + 1);
+ fread(buffer, 1, file_entry->size, src_stream);
+ buffer[file_entry->size] = '\0';
+ archive_offset += file_entry->size;
+ goto cleanup;
+ }
+ }
+ else if (function & extract_all_to_fs) {
+ struct stat oldfile;
+ int stat_res;
+ stat_res = lstat (full_name, &oldfile);
+ if (stat_res == 0) { /* The file already exists */
+ if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) {
+ if (!S_ISDIR(oldfile.st_mode)) {
+ unlink(full_name); /* Directories might not be empty etc */
+ }
+ } else {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ error_msg("%s not created: newer or same age file exists", file_entry->name);
+ }
+ seek_sub_file(src_stream, file_entry->size);
+ goto cleanup;
+ }
+ }
+ if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */
+ char *buf, *parent;
+ buf = xstrdup(full_name);
+ parent = dirname(buf);
+ if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ error_msg("couldn't create leading directories");
+ }
+ }
+ free (buf);
+ }
+ switch(file_entry->mode & S_IFMT) {
+ case S_IFREG:
+ if (file_entry->link_name) { /* Found a cpio hard link */
+ if (link(full_link_name, full_name) != 0) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ perror_msg("Cannot link from %s to '%s'",
+ file_entry->name, file_entry->link_name);
+ }
+ }
+ } else {
+ if ((dst_stream = wfopen(full_name, "w")) == NULL) {
+ *err = -1;
+ seek_sub_file(src_stream, file_entry->size);
+ goto cleanup;
+ }
+ archive_offset += file_entry->size;
+ *err = copy_file_chunk(src_stream, dst_stream, file_entry->size);
+ fclose(dst_stream);
+ }
+ break;
+ case S_IFDIR:
+ if (stat_res != 0) {
+ if (mkdir(full_name, file_entry->mode) < 0) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ perror_msg("Cannot make dir %s", full_name);
+ }
+ }
+ }
+ break;
+ case S_IFLNK:
+ if (symlink(file_entry->link_name, full_name) < 0) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name);
+ }
+ goto cleanup;
+ }
+ break;
+ case S_IFSOCK:
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFIFO:
+ if (mknod(full_name, file_entry->mode, file_entry->device) == -1) {
+ if ((function & extract_quiet) != extract_quiet) {
+ *err = -1;
+ perror_msg("Cannot create node %s", file_entry->name);
+ }
+ goto cleanup;
+ }
+ break;
+ default:
+ *err = -1;
+ perror_msg("Don't know how to handle %s", full_name);
+
+ }
+
+ /* Changing a symlink's properties normally changes the properties of the
+ * file pointed to, so dont try and change the date or mode, lchown does
+ * does the right thing, but isnt available in older versions of libc */
+ if (S_ISLNK(file_entry->mode)) {
+#if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1)
+ lchown(full_name, file_entry->uid, file_entry->gid);
+#endif
+ } else {
+ if (function & extract_preserve_date) {
+ t.actime = file_entry->mtime;
+ t.modtime = file_entry->mtime;
+ utime(full_name, &t);
+ }
+ chown(full_name, file_entry->uid, file_entry->gid);
+ chmod(full_name, file_entry->mode);
+ }
+ } else {
+ /* If we arent extracting data we have to skip it,
+ * if data size is 0 then then just do it anyway
+ * (saves testing for it) */
+ seek_sub_file(src_stream, file_entry->size);
+ }
+
+ /* extract_list and extract_verbose_list can be used in conjunction
+ * with one of the above four extraction functions, so do this seperately */
+ if (function & extract_verbose_list) {
+ fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode),
+ file_entry->uid, file_entry->gid,
+ (int) file_entry->size, time_string(file_entry->mtime));
+ }
+ if ((function & extract_list) || (function & extract_verbose_list)){
+ /* fputs doesnt add a trailing \n, so use fprintf */
+ fprintf(out_stream, "%s\n", file_entry->name);
+ }
+
+cleanup:
+ free(full_name);
+ if ( full_link_name )
+ free(full_link_name);
+
+ return buffer;
+}
+
+static char *
+unarchive(FILE *src_stream, FILE *out_stream,
+ file_header_t *(*get_headers)(FILE *),
+ void (*free_headers)(file_header_t *),
+ const int extract_function,
+ const char *prefix,
+ const char **extract_names,
+ int *err)
+{
+ file_header_t *file_entry;
+ int extract_flag;
+ int i;
+ char *buffer = NULL;
+
+ *err = 0;
+
+ archive_offset = 0;
+ while ((file_entry = get_headers(src_stream)) != NULL) {
+ extract_flag = TRUE;
+
+ if (extract_names != NULL) {
+ int found_flag = FALSE;
+ char *p = file_entry->name;
+
+ if (p[0] == '.' && p[1] == '/')
+ p += 2;
+
+ for(i = 0; extract_names[i] != 0; i++) {
+ if (strcmp(extract_names[i], p) == 0) {
+ found_flag = TRUE;
+ break;
+ }
+ }
+ if (extract_function & extract_exclude_list) {
+ if (found_flag == TRUE) {
+ extract_flag = FALSE;
+ }
+ } else {
+ /* If its not found in the include list dont extract it */
+ if (found_flag == FALSE) {
+ extract_flag = FALSE;
+ }
+ }
+ }
+
+ if (extract_flag == TRUE) {
+ buffer = extract_archive(src_stream, out_stream,
+ file_entry, extract_function,
+ prefix, err);
+ *err = 0; /* XXX: ignore extraction errors */
+ if (*err) {
+ free_headers(file_entry);
+ break;
+ }
+ } else {
+ /* seek past the data entry */
+ seek_sub_file(src_stream, file_entry->size);
+ }
+ free_headers(file_entry);
+ }
+
+ return buffer;
+}
+
+static file_header_t *
+get_header_ar(FILE *src_stream)
+{
+ file_header_t *typed;
+ union {
+ char raw[60];
+ struct {
+ char name[16];
+ char date[12];
+ char uid[6];
+ char gid[6];
+ char mode[8];
+ char size[10];
+ char magic[2];
+ } formated;
+ } ar;
+ static char *ar_long_names;
+
+ if (fread(ar.raw, 1, 60, src_stream) != 60) {
+ return(NULL);
+ }
+ archive_offset += 60;
+ /* align the headers based on the header magic */
+ if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) {
+ /* some version of ar, have an extra '\n' after each data entry,
+ * this puts the next header out by 1 */
+ if (ar.formated.magic[1] != '`') {
+ error_msg("Invalid magic");
+ return(NULL);
+ }
+ /* read the next char out of what would be the data section,
+ * if its a '\n' then it is a valid header offset by 1*/
+ archive_offset++;
+ if (fgetc(src_stream) != '\n') {
+ error_msg("Invalid magic");
+ return(NULL);
+ }
+ /* fix up the header, we started reading 1 byte too early */
+ /* raw_header[60] wont be '\n' as it should, but it doesnt matter */
+ memmove(ar.raw, &ar.raw[1], 59);
+ }
+
+ typed = (file_header_t *) xcalloc(1, sizeof(file_header_t));
+
+ typed->size = (size_t) atoi(ar.formated.size);
+ /* long filenames have '/' as the first character */
+ if (ar.formated.name[0] == '/') {
+ if (ar.formated.name[1] == '/') {
+ /* If the second char is a '/' then this entries data section
+ * stores long filename for multiple entries, they are stored
+ * in static variable long_names for use in future entries */
+ ar_long_names = (char *) xrealloc(ar_long_names, typed->size);
+ fread(ar_long_names, 1, typed->size, src_stream);
+ archive_offset += typed->size;
+ /* This ar entries data section only contained filenames for other records
+ * they are stored in the static ar_long_names for future reference */
+ return (get_header_ar(src_stream)); /* Return next header */
+ } else if (ar.formated.name[1] == ' ') {
+ /* This is the index of symbols in the file for compilers */
+ seek_sub_file(src_stream, typed->size);
+ return (get_header_ar(src_stream)); /* Return next header */
+ } else {
+ /* The number after the '/' indicates the offset in the ar data section
+ (saved in variable long_name) that conatains the real filename */
+ if (!ar_long_names) {
+ error_msg("Cannot resolve long file name");
+ return (NULL);
+ }
+ typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1]));
+ }
+ } else {
+ /* short filenames */
+ typed->name = xcalloc(1, 16);
+ strncpy(typed->name, ar.formated.name, 16);
+ }
+ typed->name[strcspn(typed->name, " /")]='\0';
+
+ /* convert the rest of the now valid char header to its typed struct */
+ parse_mode(ar.formated.mode, &typed->mode);
+ typed->mtime = atoi(ar.formated.date);
+ typed->uid = atoi(ar.formated.uid);
+ typed->gid = atoi(ar.formated.gid);
+
+ return(typed);
+}
+
+static void
+free_header_ar(file_header_t *ar_entry)
+{
+ if (ar_entry == NULL)
+ return;
+
+ free(ar_entry->name);
+ if (ar_entry->link_name)
+ free(ar_entry->link_name);
+
+ free(ar_entry);
+}
+
+
+static file_header_t *
+get_header_tar(FILE *tar_stream)
+{
+ union {
+ unsigned char raw[512];
+ struct {
+ char name[100]; /* 0-99 */
+ char mode[8]; /* 100-107 */
+ char uid[8]; /* 108-115 */
+ char gid[8]; /* 116-123 */
+ char size[12]; /* 124-135 */
+ char mtime[12]; /* 136-147 */
+ char chksum[8]; /* 148-155 */
+ char typeflag; /* 156-156 */
+ char linkname[100]; /* 157-256 */
+ char magic[6]; /* 257-262 */
+ char version[2]; /* 263-264 */
+ char uname[32]; /* 265-296 */
+ char gname[32]; /* 297-328 */
+ char devmajor[8]; /* 329-336 */
+ char devminor[8]; /* 337-344 */
+ char prefix[155]; /* 345-499 */
+ char padding[12]; /* 500-512 */
+ } formated;
+ } tar;
+ file_header_t *tar_entry = NULL;
+ long i;
+ long sum = 0;
+
+ if (archive_offset % 512 != 0) {
+ seek_sub_file(tar_stream, 512 - (archive_offset % 512));
+ }
+
+ if (fread(tar.raw, 1, 512, tar_stream) != 512) {
+ /* Unfortunately its common for tar files to have all sorts of
+ * trailing garbage, fail silently */
+// error_msg("Couldnt read header");
+ return(NULL);
+ }
+ archive_offset += 512;
+
+ /* Check header has valid magic, unfortunately some tar files
+ * have empty (0'ed) tar entries at the end, which will
+ * cause this to fail, so fail silently for now
+ */
+ if (strncmp(tar.formated.magic, "ustar", 5) != 0) {
+#ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY
+ if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0)
+#endif
+ return(NULL);
+ }
+
+ /* Do checksum on headers */
+ for (i = 0; i < 148 ; i++) {
+ sum += tar.raw[i];
+ }
+ sum += ' ' * 8;
+ for (i = 156; i < 512 ; i++) {
+ sum += tar.raw[i];
+ }
+ if (sum != strtol(tar.formated.chksum, NULL, 8)) {
+ if ( strtol(tar.formated.chksum,NULL,8) != 0 )
+ error_msg("Invalid tar header checksum");
+ return(NULL);
+ }
+
+ /* convert to type'ed variables */
+ tar_entry = xcalloc(1, sizeof(file_header_t));
+
+
+
+ // tar_entry->name = xstrdup(tar.formated.name);
+
+/*
+ parse_mode(tar.formated.mode, &tar_entry->mode);
+*/
+ tar_entry->mode = 07777 & strtol(tar.formated.mode, NULL, 8);
+
+ tar_entry->uid = strtol(tar.formated.uid, NULL, 8);
+ tar_entry->gid = strtol(tar.formated.gid, NULL, 8);
+ tar_entry->size = strtol(tar.formated.size, NULL, 8);
+ tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8);
+
+ tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) +
+ strtol(tar.formated.devminor, NULL, 8);
+
+ /* Fix mode, used by the old format */
+ switch (tar.formated.typeflag) {
+ /* hard links are detected as regular files with 0 size and a link name */
+ case '1':
+ tar_entry->mode |= S_IFREG ;
+ break;
+ case 0:
+ case '0':
+
+# ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY
+ if (last_char_is(tar_entry->name, '/')) {
+ tar_entry->mode |= S_IFDIR;
+ } else
+# endif
+ tar_entry->mode |= S_IFREG;
+ break;
+ case '2':
+ tar_entry->mode |= S_IFLNK;
+ break;
+ case '3':
+ tar_entry->mode |= S_IFCHR;
+ break;
+ case '4':
+ tar_entry->mode |= S_IFBLK;
+ break;
+ case '5':
+ tar_entry->mode |= S_IFDIR;
+ break;
+ case '6':
+ tar_entry->mode |= S_IFIFO;
+ break;
+# ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+ case 'L': {
+ longname = xmalloc(tar_entry->size + 1);
+ if(fread(longname, tar_entry->size, 1, tar_stream) != 1)
+ return NULL;
+ longname[tar_entry->size] = '\0';
+ archive_offset += tar_entry->size;
+
+ return(get_header_tar(tar_stream));
+ }
+ case 'K': {
+ linkname = xmalloc(tar_entry->size + 1);
+ if(fread(linkname, tar_entry->size, 1, tar_stream) != 1)
+ return NULL;
+ linkname[tar_entry->size] = '\0';
+ archive_offset += tar_entry->size;
+
+ return(get_header_tar(tar_stream));
+ }
+ case 'D':
+ case 'M':
+ case 'N':
+ case 'S':
+ case 'V':
+ perror_msg("Ignoring GNU extension type %c", tar.formated.typeflag);
+# endif
+ default:
+ perror_msg("Unknown typeflag: 0x%x", tar.formated.typeflag);
+ break;
+
+ }
+
+
+#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS
+ if (longname) {
+ tar_entry->name = longname;
+ longname = NULL;
+ } else
+#endif
+ {
+ tar_entry->name = xstrndup(tar.formated.name, 100);
+
+ if (tar.formated.prefix[0]) {
+ char *temp = tar_entry->name;
+ char *prefixTemp = xstrndup(tar.formated.prefix, 155);
+ tar_entry->name = concat_path_file(prefixTemp, temp);
+ free(temp);
+ free(prefixTemp);
+ }
+ }
+
+ if (linkname) {
+ tar_entry->link_name = linkname;
+ linkname = NULL;
+ } else
+ {
+ tar_entry->link_name = *tar.formated.linkname != '\0' ?
+ xstrndup(tar.formated.linkname, 100) : NULL;
+ }
+
+ return(tar_entry);
+}
+
+static void
+free_header_tar(file_header_t *tar_entry)
+{
+ if (tar_entry == NULL)
+ return;
+
+ free(tar_entry->name);
+ if (tar_entry->link_name)
+ free(tar_entry->link_name);
+
+ free(tar_entry);
+}
+
+char *
+deb_extract(const char *package_filename, FILE *out_stream,
+ const int extract_function, const char *prefix,
+ const char *filename, int *err)
+{
+ FILE *deb_stream = NULL;
+ file_header_t *ar_header = NULL;
+ const char **file_list = NULL;
+ char *output_buffer = NULL;
+ char *ared_file = NULL;
+ char ar_magic[8];
+ int gz_err;
+
+ *err = 0;
+
+ if (filename != NULL) {
+ file_list = xmalloc(sizeof(char *) * 2);
+ file_list[0] = filename;
+ file_list[1] = NULL;
+ }
+
+ if (extract_function & extract_control_tar_gz) {
+ ared_file = "control.tar.gz";
+ }
+ else if (extract_function & extract_data_tar_gz) {
+ ared_file = "data.tar.gz";
+ } else {
+ opkg_msg(ERROR, "Internal error: extract_function=%x\n",
+ extract_function);
+ *err = -1;
+ goto cleanup;
+ }
+
+ /* open the debian package to be worked on */
+ deb_stream = wfopen(package_filename, "r");
+ if (deb_stream == NULL) {
+ *err = -1;
+ goto cleanup;
+ }
+ /* set the buffer size */
+ setvbuf(deb_stream, NULL, _IOFBF, 0x8000);
+
+ /* check ar magic */
+ fread(ar_magic, 1, 8, deb_stream);
+
+ if (strncmp(ar_magic,"!<arch>",7) == 0) {
+ archive_offset = 8;
+
+ while ((ar_header = get_header_ar(deb_stream)) != NULL) {
+ if (strcmp(ared_file, ar_header->name) == 0) {
+ int gunzip_pid = 0;
+ FILE *uncompressed_stream;
+ /* open a stream of decompressed data */
+ uncompressed_stream = gz_open(deb_stream, &gunzip_pid);
+ if (uncompressed_stream == NULL) {
+ *err = -1;
+ goto cleanup;
+ }
+
+ archive_offset = 0;
+ output_buffer = unarchive(uncompressed_stream,
+ out_stream, get_header_tar,
+ free_header_tar,
+ extract_function, prefix,
+ file_list, err);
+ fclose(uncompressed_stream);
+ gz_err = gz_close(gunzip_pid);
+ if (gz_err)
+ *err = -1;
+ free_header_ar(ar_header);
+ break;
+ }
+ if (fseek(deb_stream, ar_header->size, SEEK_CUR) == -1) {
+ opkg_perror(ERROR, "Couldn't fseek into %s", package_filename);
+ *err = -1;
+ free_header_ar(ar_header);
+ goto cleanup;
+ }
+ free_header_ar(ar_header);
+ }
+ goto cleanup;
+ } else if (strncmp(ar_magic, "\037\213", 2) == 0) {
+ /* it's a gz file, let's assume it's an opkg */
+ int unzipped_opkg_pid;
+ FILE *unzipped_opkg_stream;
+ file_header_t *tar_header;
+ archive_offset = 0;
+ if (fseek(deb_stream, 0, SEEK_SET) == -1) {
+ opkg_perror(ERROR, "Couldn't fseek into %s", package_filename);
+ *err = -1;
+ goto cleanup;
+ }
+ unzipped_opkg_stream = gz_open(deb_stream, &unzipped_opkg_pid);
+ if (unzipped_opkg_stream == NULL) {
+ *err = -1;
+ goto cleanup;
+ }
+
+ /* walk through outer tar file to find ared_file */
+ while ((tar_header = get_header_tar(unzipped_opkg_stream)) != NULL) {
+ int name_offset = 0;
+ if (strncmp(tar_header->name, "./", 2) == 0)
+ name_offset = 2;
+ if (strcmp(ared_file, tar_header->name+name_offset) == 0) {
+ int gunzip_pid = 0;
+ FILE *uncompressed_stream;
+ /* open a stream of decompressed data */
+ uncompressed_stream = gz_open(unzipped_opkg_stream, &gunzip_pid);
+ if (uncompressed_stream == NULL) {
+ *err = -1;
+ goto cleanup;
+ }
+ archive_offset = 0;
+
+ output_buffer = unarchive(uncompressed_stream,
+ out_stream,
+ get_header_tar,
+ free_header_tar,
+ extract_function,
+ prefix,
+ file_list,
+ err);
+
+ free_header_tar(tar_header);
+ fclose(uncompressed_stream);
+ gz_err = gz_close(gunzip_pid);
+ if (gz_err)
+ *err = -1;
+ break;
+ }
+ seek_sub_file(unzipped_opkg_stream, tar_header->size);
+ free_header_tar(tar_header);
+ }
+ fclose(unzipped_opkg_stream);
+ gz_err = gz_close(unzipped_opkg_pid);
+ if (gz_err)
+ *err = -1;
+
+ goto cleanup;
+ } else {
+ *err = -1;
+ error_msg("%s: invalid magic", package_filename);
+ }
+
+cleanup:
+ if (deb_stream)
+ fclose(deb_stream);
+ if (file_list)
+ free(file_list);
+
+ return output_buffer;
+}
diff --git a/src/libbb/unzip.c b/src/libbb/unzip.c
new file mode 100644
index 0000000..435effb
--- /dev/null
+++ b/src/libbb/unzip.c
@@ -0,0 +1,1021 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * gunzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersee@debian.org> to support
+ * files as well as stdin/stdout, and to generally behave itself wrt
+ * command line handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of
+ * standard busybox functions by Glenn McGrath <bug1@optushome.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libbb.h"
+
+static FILE *in_file, *out_file;
+
+static unsigned char *window;
+static unsigned long *crc_table = NULL;
+
+static unsigned long crc; /* shift register contents */
+
+/*
+ * window size--must be a power of two, and
+ * at least 32K for zip's deflate method
+ */
+static const int WSIZE = 0x8000;
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */
+static const int N_MAX = 288; /* maximum number of codes in any set */
+
+static long bytes_out; /* number of output bytes */
+static unsigned long outcnt; /* bytes in output buffer */
+
+static unsigned hufts; /* track memory usage */
+static unsigned long bb; /* bit buffer */
+static unsigned bk; /* bits in bit buffer */
+
+typedef struct huft_s {
+ unsigned char e; /* number of extra bits or operation */
+ unsigned char b; /* number of bits in this code or subcode */
+ union {
+ unsigned short n; /* literal, length base, or distance base */
+ struct huft_s *t; /* pointer to next level of table */
+ } v;
+} huft_t;
+
+static const unsigned short mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+//static int error_number = 0;
+/* ========================================================================
+ * Signal and error handler.
+ */
+
+static void abort_gzip()
+{
+ error_msg("gzip aborted\n");
+ _exit(-1);
+}
+
+static void make_crc_table()
+{
+ unsigned long table_entry; /* crc shift register */
+ unsigned long poly = 0; /* polynomial exclusive-or pattern */
+ int i; /* counter for all possible eight bit values */
+ int k; /* byte being shifted into crc apparatus */
+
+ /* terms of polynomial defining this crc (except x^32): */
+ static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* initial shift register value */
+ crc = 0xffffffffL;
+ crc_table = (unsigned long *) xmalloc(256 * sizeof(unsigned long));
+
+ /* Make exclusive-or pattern from polynomial (0xedb88320) */
+ for (i = 0; i < sizeof(p)/sizeof(int); i++)
+ poly |= 1L << (31 - p[i]);
+
+ /* Compute and print table of CRC's, five per line */
+ for (i = 0; i < 256; i++) {
+ table_entry = i;
+ /* The idea to initialize the register with the byte instead of
+ * zero was stolen from Haruhiko Okumura's ar002
+ */
+ for (k = 8; k; k--) {
+ table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1;
+ }
+ crc_table[i]=table_entry;
+ }
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+ int n;
+
+ if (outcnt == 0)
+ return;
+
+ for (n = 0; n < outcnt; n++) {
+ crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8);
+ }
+
+ if (fwrite(window, 1, outcnt, out_file) != outcnt) {
+ /*
+ * The Parent process may not be interested in all the data we have,
+ * in which case it will rudely close its end of the pipe and
+ * wait for us to exit.
+ */
+ if (errno == EPIPE)
+ _exit(EXIT_SUCCESS);
+
+ error_msg("Couldnt write");
+ _exit(EXIT_FAILURE);
+ }
+ bytes_out += (unsigned long) outcnt;
+ outcnt = 0;
+}
+
+/*
+ * Free the malloc'ed tables built by huft_build(), which makes a linked
+ * list of the tables it made, with the links in a dummy first entry of
+ * each table.
+ * t: table to free
+ */
+static int huft_free(huft_t *t)
+{
+ huft_t *p, *q;
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (huft_t *) NULL) {
+ q = (--p)->v.t;
+ free((char *) p);
+ p = q;
+ }
+ return 0;
+}
+
+/* Given a list of code lengths and a maximum table size, make a set of
+ * tables to decode that set of codes. Return zero on success, one if
+ * the given code set is incomplete (the tables are still built in this
+ * case), two if the input is invalid (all zero length codes or an
+ * oversubscribed set of lengths), and three if not enough memory.
+ *
+ * b: code lengths in bits (all assumed <= BMAX)
+ * n: number of codes (assumed <= N_MAX)
+ * s: number of simple-valued codes (0..s-1)
+ * d: list of base values for non-simple codes
+ * e: list of extra bits for non-simple codes
+ * t: result: starting table
+ * m: maximum lookup bits, returns actual
+ */
+static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s,
+ const unsigned short *d, const unsigned short *e, huft_t **t, int *m)
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX + 1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ unsigned i; /* counter, current code */
+ unsigned j; /* counter */
+ int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ unsigned *p; /* pointer into c[], b[], or v[] */
+ huft_t *q; /* points to current table */
+ huft_t r; /* table entry for structure assignment */
+ huft_t *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX + 1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+ /* Generate counts for each bit length */
+ memset ((void *)(c), 0, sizeof(c));
+ p = b;
+ i = n;
+ do {
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) { /* null input--all zero length codes */
+ *t = (huft_t *) NULL;
+ *m = 0;
+ return 0;
+ }
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned) l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned) l > i)
+ l = i;
+ *m = l;
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1;
+ xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+ /* Make a table of values in order of bit lengths */
+ p = b;
+ i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (huft_t *) NULL; /* just to keep compilers happy */
+ q = (huft_t *) NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++) {
+ a = c[k];
+ while (a--) {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l) {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) { /* try smaller tables up to z bits */
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) {
+ if (h) {
+ huft_free(u[0]);
+ }
+ return 3; /* not enough memory */
+ }
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h) {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (unsigned char) l; /* bits to dump before this table */
+ r.e = (unsigned char) (16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h - 1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (unsigned char) (k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s) {
+ r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (unsigned short) (*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ } else {
+ r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h]) {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+/*
+ * inflate (decompress) the codes in a deflated (compressed) block.
+ * Return an error code or zero if it all goes ok.
+ *
+ * tl, td: literal/length and distance decoder tables
+ * bl, bd: number of bits decoded by tl[] and td[]
+ */
+static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd)
+{
+ unsigned long e; /* table entry flag/number of extra bits */
+ unsigned long n, d; /* length and index for copy */
+ unsigned long w; /* current window position */
+ huft_t *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ unsigned long b; /* bit buffer */
+ unsigned k; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = outcnt; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) { /* do until end of block */
+ while (k < (unsigned) bl) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ if ((e = (t = tl + ((unsigned) b & ml))->e) > 16)
+ do {
+ if (e == 99) {
+ return 1;
+ }
+ b >>= t->b;
+ k -= t->b;
+ e -= 16;
+ while (k < e) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
+ b >>= t->b;
+ k -= t->b;
+ if (e == 16) { /* then it's a literal */
+ window[w++] = (unsigned char) t->v.n;
+ if (w == WSIZE) {
+ outcnt=(w),
+ flush_window();
+ w = 0;
+ }
+ } else { /* it's an EOB or a length */
+
+ /* exit if end of block */
+ if (e == 15) {
+ break;
+ }
+
+ /* get length of block to copy */
+ while (k < e) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ n = t->v.n + ((unsigned) b & mask_bits[e]);
+ b >>= e;
+ k -= e;
+
+ /* decode distance of block to copy */
+ while (k < (unsigned) bd) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+
+ if ((e = (t = td + ((unsigned) b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ b >>= t->b;
+ k -= t->b;
+ e -= 16;
+ while (k < e) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16);
+ b >>= t->b;
+ k -= t->b;
+ while (k < e) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ d = w - t->v.n - ((unsigned) b & mask_bits[e]);
+ b >>= e;
+ k -= e;
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) { /* (this test assumes unsigned comparison) */
+ memcpy(window + w, window + d, e);
+ w += e;
+ d += e;
+ } else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ window[w++] = window[d++];
+ } while (--e);
+ if (w == WSIZE) {
+ outcnt=(w),
+ flush_window();
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+ /* restore the globals from the locals */
+ outcnt = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+/*
+ * decompress an inflated block
+ * e: last block flag
+ *
+ * GLOBAL VARIABLES: bb, kk,
+ */
+static int inflate_block(int *e)
+{
+ unsigned t; /* block type */
+ unsigned long b; /* bit buffer */
+ unsigned k; /* number of bits in bit buffer */
+ static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+ };
+ /* note: see note #13 above about the 258 in this list. */
+ static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
+ }; /* 99==invalid */
+ static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577
+ };
+ static unsigned short cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13
+ };
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+ /* read in last block bit */
+ while (k < 1) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ *e = (int) b & 1;
+ b >>= 1;
+ k -= 1;
+
+ /* read in block type */
+ while (k < 2) {
+ b |= ((unsigned long)fgetc(in_file)) << k;
+ k += 8;
+ }
+ t = (unsigned) b & 3;
+ b >>= 2;
+ k -= 2;
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+ /* inflate that block type */
+ switch (t) {
+ case 0: /* Inflate stored */
+ {
+ unsigned long n; /* number of bytes in block */
+ unsigned long w; /* current window position */
+ unsigned long b_stored; /* bit buffer */
+ unsigned long k_stored; /* number of bits in bit buffer */
+
+ /* make local copies of globals */
+ b_stored = bb; /* initialize bit buffer */
+ k_stored = bk;
+ w = outcnt; /* initialize window position */
+
+ /* go to byte boundary */
+ n = k_stored & 7;
+ b_stored >>= n;
+ k_stored -= n;
+
+ /* get the length and its complement */
+ while (k_stored < 16) {
+ b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
+ k_stored += 8;
+ }
+ n = ((unsigned) b_stored & 0xffff);
+ b_stored >>= 16;
+ k_stored -= 16;
+ while (k_stored < 16) {
+ b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
+ k_stored += 8;
+ }
+ if (n != (unsigned) ((~b_stored) & 0xffff)) {
+ return 1; /* error in compressed data */
+ }
+ b_stored >>= 16;
+ k_stored -= 16;
+
+ /* read and output the compressed data */
+ while (n--) {
+ while (k_stored < 8) {
+ b_stored |= ((unsigned long)fgetc(in_file)) << k_stored;
+ k_stored += 8;
+ }
+ window[w++] = (unsigned char) b_stored;
+ if (w == (unsigned long)WSIZE) {
+ outcnt=(w),
+ flush_window();
+ w = 0;
+ }
+ b_stored >>= 8;
+ k_stored -= 8;
+ }
+
+ /* restore the globals from the locals */
+ outcnt = w; /* restore global window pointer */
+ bb = b_stored; /* restore global bit buffer */
+ bk = k_stored;
+ return 0;
+ }
+ case 1: /* Inflate fixed
+ * decompress an inflated type 1 (fixed Huffman codes) block. We should
+ * either replace this with a custom decoder, or at least precompute the
+ * Huffman tables.
+ */
+ {
+ int i; /* temporary variable */
+ huft_t *tl; /* literal/length code table */
+ huft_t *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned int l[288]; /* length list for huft_build */
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++) {
+ l[i] = 8;
+ }
+ for (; i < 256; i++) {
+ l[i] = 9;
+ }
+ for (; i < 280; i++) {
+ l[i] = 7;
+ }
+ for (; i < 288; i++) { /* make a complete, but wrong code set */
+ l[i] = 8;
+ }
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
+ return i;
+ }
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) { /* make an incomplete code set */
+ l[i] = 5;
+ }
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) {
+ huft_free(tl);
+ return i;
+ }
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd)) {
+ huft_free(tl);
+ huft_free(td);
+ return 1;
+ }
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+ }
+ case 2: /* Inflate dynamic */
+ {
+ /* Tables for deflate from PKZIP's appnote.txt. */
+ static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+ };
+ int dbits = 6; /* bits in base distance lookup table */
+ int lbits = 9; /* bits in base literal/length lookup table */
+
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ huft_t *tl; /* literal/length code table */
+ huft_t *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+
+ unsigned ll[286 + 30]; /* literal/length and distance code lengths */
+ unsigned long b_dynamic; /* bit buffer */
+ unsigned k_dynamic; /* number of bits in bit buffer */
+
+ /* make local bit buffer */
+ b_dynamic = bb;
+ k_dynamic = bk;
+
+ /* read in table lengths */
+ while (k_dynamic < 5) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */
+ b_dynamic >>= 5;
+ k_dynamic -= 5;
+ while (k_dynamic < 5) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */
+ b_dynamic >>= 5;
+ k_dynamic -= 5;
+ while (k_dynamic < 4) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */
+ b_dynamic >>= 4;
+ k_dynamic -= 4;
+ if (nl > 286 || nd > 30) {
+ return 1; /* bad lengths */
+ }
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++) {
+ while (k_dynamic < 3) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ ll[border[j]] = (unsigned) b_dynamic & 7;
+ b_dynamic >>= 3;
+ k_dynamic -= 3;
+ }
+ for (; j < 19; j++) {
+ ll[border[j]] = 0;
+ }
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) {
+ if (i == 1) {
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned) i < n) {
+ while (k_dynamic < (unsigned) bl) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ j = (td = tl + ((unsigned) b_dynamic & m))->b;
+ b_dynamic >>= j;
+ k_dynamic -= j;
+ j = td->v.n;
+ if (j < 16) { /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ }
+ else if (j == 16) { /* repeat last length 3 to 6 times */
+ while (k_dynamic < 2) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ j = 3 + ((unsigned) b_dynamic & 3);
+ b_dynamic >>= 2;
+ k_dynamic -= 2;
+ if ((unsigned) i + j > n) {
+ return 1;
+ }
+ while (j--) {
+ ll[i++] = l;
+ }
+ } else if (j == 17) { /* 3 to 10 zero length codes */
+ while (k_dynamic < 3) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ j = 3 + ((unsigned) b_dynamic & 7);
+ b_dynamic >>= 3;
+ k_dynamic -= 3;
+ if ((unsigned) i + j > n) {
+ return 1;
+ }
+ while (j--) {
+ ll[i++] = 0;
+ }
+ l = 0;
+ } else { /* j == 18: 11 to 138 zero length codes */
+ while (k_dynamic < 7) {
+ b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic;
+ k_dynamic += 8;
+ }
+ j = 11 + ((unsigned) b_dynamic & 0x7f);
+ b_dynamic >>= 7;
+ k_dynamic -= 7;
+ if ((unsigned) i + j > n) {
+ return 1;
+ }
+ while (j--) {
+ ll[i++] = 0;
+ }
+ l = 0;
+ }
+ }
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+ /* restore the global bit buffer */
+ bb = b_dynamic;
+ bk = k_dynamic;
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) {
+ if (i == 1) {
+ error_msg("Incomplete literal tree");
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) {
+ if (i == 1) {
+ error_msg("incomplete distance tree");
+ huft_free(td);
+ }
+ huft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd)) {
+ huft_free(tl);
+ huft_free(td);
+ return 1;
+ }
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+ }
+ default:
+ /* bad block type */
+ return 2;
+ }
+}
+
+/*
+ * decompress an inflated entry
+ *
+ * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
+ */
+static int inflate()
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h = 0; /* maximum struct huft's malloc'ed */
+
+ /* initialize window, bit buffer */
+ outcnt = 0;
+ bk = 0;
+ bb = 0;
+
+ /* decompress until the last block */
+ do {
+ hufts = 0;
+ if ((r = inflate_block(&e)) != 0) {
+ return r;
+ }
+ if (hufts > h) {
+ h = hufts;
+ }
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte. */
+ while (bk >= 8) {
+ bk -= 8;
+ ungetc((bb << bk), in_file);
+ }
+
+ /* flush out window */
+ flush_window();
+
+ /* return success */
+ return 0;
+}
+
+/* ===========================================================================
+ * Unzip in to out. This routine works on both gzip and pkzip files.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets inptr to insize-1 included.
+ * The magic header has already been checked. The output buffer is cleared.
+ * in, out: input and output file descriptors
+ */
+extern int unzip(FILE *l_in_file, FILE *l_out_file)
+{
+ const int extra_field = 0x04; /* bit 2 set: extra field present */
+ const int orig_name = 0x08; /* bit 3 set: original file name present */
+ const int comment = 0x10; /* bit 4 set: file comment present */
+ unsigned char buf[8]; /* extended local header */
+ unsigned char flags; /* compression flags */
+ char magic[2]; /* magic header */
+ int method;
+ typedef void (*sig_type) (int);
+ int exit_code=0; /* program exit code */
+ int i;
+
+ in_file = l_in_file;
+ out_file = l_out_file;
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGINT, (sig_type) abort_gzip);
+ }
+#ifdef SIGTERM
+// if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+// (void) signal(SIGTERM, (sig_type) abort_gzip);
+// }
+#endif
+#ifdef SIGHUP
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+ (void) signal(SIGHUP, (sig_type) abort_gzip);
+ }
+#endif
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /* Allocate all global buffers (for DYN_ALLOC option) */
+ window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
+ outcnt = 0;
+ bytes_out = 0L;
+
+ magic[0] = fgetc(in_file);
+ magic[1] = fgetc(in_file);
+
+ /* Magic header for gzip files, 1F 8B = \037\213 */
+ if (memcmp(magic, "\037\213", 2) != 0) {
+ error_msg("Invalid gzip magic");
+ return EXIT_FAILURE;
+ }
+
+ method = (int) fgetc(in_file);
+ if (method != 8) {
+ error_msg("unknown method %d -- get newer version of gzip", method);
+ exit_code = 1;
+ return -1;
+ }
+
+ flags = (unsigned char) fgetc(in_file);
+
+ /* Ignore time stamp(4), extra flags(1), OS type(1) */
+ for (i = 0; i < 6; i++)
+ fgetc(in_file);
+
+ if ((flags & extra_field) != 0) {
+ size_t extra;
+ extra = fgetc(in_file);
+ extra += fgetc(in_file) << 8;
+
+ for (i = 0; i < extra; i++)
+ fgetc(in_file);
+ }
+
+ /* Discard original name if any */
+ if ((flags & orig_name) != 0) {
+ while (fgetc(in_file) != 0); /* null */
+ }
+
+ /* Discard file comment if any */
+ if ((flags & comment) != 0) {
+ while (fgetc(in_file) != 0); /* null */
+ }
+
+ if (method < 0) {
+ return(exit_code);
+ }
+
+ make_crc_table();
+
+ /* Decompress */
+ if (method == 8) {
+
+ int res = inflate();
+
+ if (res == 3) {
+ perror_msg("inflate");
+ exit_code = 1;
+ } else if (res != 0) {
+ error_msg("invalid compressed data--format violated");
+ exit_code = 1;
+ }
+
+ } else {
+ error_msg("internal error, invalid method");
+ exit_code = 1;
+ }
+
+ /* Get the crc and original length
+ * crc32 (see algorithm.doc)
+ * uncompressed input size modulo 2^32
+ */
+ fread(buf, 1, 8, in_file);
+
+ /* Validate decompression - crc */
+ if (!exit_code && (unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) {
+ error_msg("invalid compressed data--crc error");
+ exit_code = 1;
+ }
+ /* Validate decompression - size */
+ if (!exit_code && ((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) {
+ error_msg("invalid compressed data--length error");
+ exit_code = 1;
+ }
+
+ free(window);
+ free(crc_table);
+
+ window = NULL;
+ crc_table = NULL;
+
+ return exit_code;
+}
diff --git a/src/libbb/wfopen.c b/src/libbb/wfopen.c
new file mode 100644
index 0000000..f58ec90
--- /dev/null
+++ b/src/libbb/wfopen.c
@@ -0,0 +1,44 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "libbb.h"
+
+FILE *wfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL) {
+ perror_msg("%s", path);
+ errno = 0;
+ }
+ return fp;
+}
+
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/xfuncs.c b/src/libbb/xfuncs.c
new file mode 100644
index 0000000..f577315
--- /dev/null
+++ b/src/libbb/xfuncs.c
@@ -0,0 +1,93 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libbb.h"
+
+
+extern void *xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (ptr == NULL && size != 0)
+ perror_msg_and_die("malloc");
+ return ptr;
+}
+
+extern void *xrealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL && size != 0)
+ perror_msg_and_die("realloc");
+ return ptr;
+}
+
+extern void *xcalloc(size_t nmemb, size_t size)
+{
+ void *ptr = calloc(nmemb, size);
+ if (ptr == NULL && nmemb != 0 && size != 0)
+ perror_msg_and_die("calloc");
+ return ptr;
+}
+
+extern char * xstrdup (const char *s) {
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+
+ t = strdup (s);
+
+ if (t == NULL)
+ perror_msg_and_die("strdup");
+
+ return t;
+}
+
+extern char * xstrndup (const char *s, int n) {
+ char *t;
+
+ if (s == NULL)
+ error_msg_and_die("xstrndup bug");
+
+ t = xmalloc(++n);
+
+ return safe_strncpy(t,s,n);
+}
+
+FILE *xfopen(const char *path, const char *mode)
+{
+ FILE *fp;
+ if ((fp = fopen(path, mode)) == NULL)
+ perror_msg_and_die("%s", path);
+ return fp;
+}
+
+/* END CODE */
+/*
+Local Variables:
+c-file-style: "linux"
+c-basic-offset: 4
+tab-width: 4
+End:
+*/
diff --git a/src/libbb/xreadlink.c b/src/libbb/xreadlink.c
new file mode 100644
index 0000000..7d77a3b
--- /dev/null
+++ b/src/libbb/xreadlink.c
@@ -0,0 +1,37 @@
+/*
+ * xreadlink.c - safe implementation of readlink.
+ * Returns a NULL on failure...
+ */
+
+#include <stdio.h>
+
+/*
+ * NOTE: This function returns a malloced char* that you will have to free
+ * yourself. You have been warned.
+ */
+
+#include <unistd.h>
+#include "libbb.h"
+
+extern char *xreadlink(const char *path)
+{
+ static const int GROWBY = 80; /* how large we will grow strings by */
+
+ char *buf = NULL;
+ int bufsize = 0, readsize = 0;
+
+ do {
+ buf = xrealloc(buf, bufsize += GROWBY);
+ readsize = readlink(path, buf, bufsize); /* 1st try */
+ if (readsize == -1) {
+ perror_msg("%s", path);
+ return NULL;
+ }
+ }
+ while (bufsize < readsize + 1);
+
+ buf[readsize] = '\0';
+
+ return buf;
+}
+
diff --git a/src/libopkg.pc.in b/src/libopkg.pc.in
new file mode 100644
index 0000000..25fe6e9
--- /dev/null
+++ b/src/libopkg.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: libopkg
+Description: opkg package manager library
+Version: @VERSION@
+Libs: -L${libdir} -lopkg
+Cflags: -I${includedir}/libopkg
+
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
+
diff --git a/src/man/.svn/all-wcprops b/src/man/.svn/all-wcprops
new file mode 100644
index 0000000..112db8b
--- /dev/null
+++ b/src/man/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 27
+/svn/!svn/ver/576/trunk/man
+END
+opkg-cl.1.in
+K 25
+svn:wc:ra_dav:version-url
+V 40
+/svn/!svn/ver/576/trunk/man/opkg-cl.1.in
+END
+Makefile.am
+K 25
+svn:wc:ra_dav:version-url
+V 39
+/svn/!svn/ver/547/trunk/man/Makefile.am
+END
+opkg-key.1.in
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/547/trunk/man/opkg-key.1.in
+END
diff --git a/src/man/.svn/entries b/src/man/.svn/entries
new file mode 100644
index 0000000..192372c
--- /dev/null
+++ b/src/man/.svn/entries
@@ -0,0 +1,130 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/man
+http://opkg.googlecode.com/svn
+
+
+
+2010-10-05T07:21:00.504250Z
+576
+google@wwsnet.net
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
+opkg-cl.1.in
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+7c14cc8295773db383557464c1e056be
+2010-10-05T07:21:00.504250Z
+576
+google@wwsnet.net
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4739
+
+Makefile.am
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+0a17269afd2b32e3abf823e2a18ce23c
+2010-08-10T05:38:23.722615Z
+547
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+34
+
+opkg-key.1.in
+file
+
+
+
+
+2012-02-03T08:11:57.579042Z
+45edca9f831cb002a02e37c0ea28833e
+2010-08-10T05:38:23.722615Z
+547
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+833
+
diff --git a/src/man/.svn/text-base/Makefile.am.svn-base b/src/man/.svn/text-base/Makefile.am.svn-base
new file mode 100644
index 0000000..6d0a535
--- /dev/null
+++ b/src/man/.svn/text-base/Makefile.am.svn-base
@@ -0,0 +1,2 @@
+man_MANS=opkg-cl.1 \
+ opkg-key.1
diff --git a/src/man/.svn/text-base/opkg-cl.1.in.svn-base b/src/man/.svn/text-base/opkg-cl.1.in.svn-base
new file mode 100644
index 0000000..2bfb792
--- /dev/null
+++ b/src/man/.svn/text-base/opkg-cl.1.in.svn-base
@@ -0,0 +1,190 @@
+.TH "@PACKAGE_NAME@" 1 "@CLEAN_DATE@" "@PACKAGE_STRING@" "User Commands"
+.SH NAME
+opkg-cl \- command line utility to install, upgrade and uninstall opkg
+software packages
+.
+.SH SYNOPSIS
+.B \fBopkg-cl\fP [\fIOPTIONS...\fP] \fIsub-command\fP [\fIARGUMENTS...\fP]
+.
+.SH DESCRIPTION
+\fBopkg-cl\fP is a simple utility to install, upgrade and uninstall opkg
+software packages. Opkg is a lightweight package management system based
+on Ipkg.
+.
+.SH "OPTIONS AND COMMANDS"
+.SS SUB-COMMANDS : PACKAGE MANIPULATION
+.TP
+\fBupdate\fR
+Update list of available packages
+.TP
+\fBupgrade\fR
+Upgrade installed packages
+.TP
+\fBinstall <\fIpackage(s)\fP>\fR
+Install \fIpackage(s)\fP
+.TP
+\fBconfigure <\fIpackage(s)\fP>\fR
+Configure unpacked \fIpackage(s)\fP
+.TP
+\fBremove <\fIpackages\fP|\fIregexp\fP>\fR
+Remove \fIpackage(s)\fP. \fIregexp\fP could be something like 'pkgname*' '*file*' or similar
+.TP
+\fBflag <\fIflag\fP> <\fIpackages\fP>\fR
+Flag \fIpackage(s)\fP. Available flags (one per invocation):
+.TS
+tab(@);
+l.
+hold
+noprune
+user
+ok
+installed
+unpacked
+.TE
+.SS INFORMATIONAL SUB-COMMANDS
+.TP
+\fBlist\fR
+List available packages
+.TP
+\fBlist-installed\fR
+List installed packages
+.TP
+\fBlist-upgradable\fR
+List installed and upgradable packages
+.TP
+\fBlist-changed-conffiles\fR
+List package configuration files which have been modified after installation
+.TP
+\fBfiles <\fIpackage\fP>\fR
+List files belonging to \fIpackage\fP
+.TP
+\fBsearch <\fIfile\fP|\fIregexp\fP>\fR
+List package providing \fIfile\fP
+.TP
+\fBinfo [\fIpackage\fP|\fIregexp\fP]\fR
+Display all info for selected packages
+.TP
+\fBstatus [\fIpackage\fP|\fIregexp\fP]\fR
+Display all statuses for selected packages
+.TP
+\fBdownload <\fIpackage\fP>\fR
+Download \fIpackage\fP to current directory
+.TP
+\fBcompare-version <\fIversion1\fP> <\fIoperator\fP> <\fIversion2\fP>\fR
+compare versions using following operators :
+.TS
+tab(@);
+c l.
+<<@less than
+<@less than or equal to
+<=@less than or equal to
+ =@equal to
+>=@greater than or equal to
+>@greater than or equal to
+>>@greater than
+.TE
+.TP
+\fBprint-architecture\fR
+List installable package architectures
+.TP
+\fBwhatdepends [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+.TP
+\fBwhatdependsrec [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+.TP
+\fBwhatprovides [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+.TP
+\fBwhatconflicts [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+.TP
+\fBwhatreplaces [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+
+.SS OPTIONS
+.TP
+\fB\-A\fR
+Query all packages not just those installed
+.
+.TP
+\fB\-v <\fIlevel\fP>, --verbosity <\fIlevel\fP>\fR
+Set verbosity level to \fIlevel\fP. Verbosity levels :
+.TS
+tab(@);
+l l.
+0@errors only
+1@normal messages (default)
+2@informative messages
+3@debug
+4@debug level 2
+.TE
+.
+.TP
+\fB\-f <\fIconf_file\fP>, \fB\--conf <\fIconf_file\fP>\fR
+Use \fIconf_file\fP as the opkg configuration file
+.TP
+\fB\--cache <\fIdirectory\fP>\fR
+Use a package cache
+.TP
+\fB\-d <\fIdest_name\fP>, \fB\--dest <\fIdest_name\fP>\fR
+Use \fIdest_name\fP as the the root directory for
+package installation, removal, upgrading. \fIdest_name\fP should be a
+defined dest name from the configuration file, (but can also be a
+directory name in a pinch).
+.TP
+\fB\-o <\fIdirectory\fP>, \fB\--offline-root <\fIdirectory\fP>\fR
+Use \fIdirectory\fP as the root directory for offline installation of
+packages.
+.TP
+\fB\--add-dest <\fIname\fP>:<\fIpath\fP>\fR
+Register \fIpath\fP as installation target \fIname\fP for use in
+conjunction with \fB\--dest\fP
+.TP
+\fB\--add-arch <\fIarch\fP>:<\fIprio\fP>\fR
+Register the package architecture \fIarch\fP with the numeric
+priority \fIprio\fP. Lower priorities take precedence.
+.SS FORCE OPTIONS
+.TP
+\fB\--force-depends \fR
+Install/remove despite failed dependencies
+.TP
+\fB\--force-maintainer \fR
+Overwrite preexisting config files
+.TP
+\fB\--force-reinstall \fR
+Reinstall package(s)
+.TP
+\fB\--force-overwrite\fR
+Overwrite files from other package(s)
+.TP
+\fB\--force-downgrade\fR
+Allow opkg-cl to downgrade packages
+.TP
+\fB\--force-space \fR
+Disable free space checks
+.TP
+\fB\--force-postinstall \fR
+Execute package postinstall scripts in offline installation mode
+.TP
+\fB\--noaction\fR
+No action \- test only
+.TP
+\fB\--download-only\fR
+No action \- download only
+.TP
+\fB\--nodeps\fR
+Do not follow dependencies
+.TP
+\fB\--force-removal-of-dependent-packages\fR
+Remove package and all dependencies
+.TP
+\fB\--autoremove\fR
+Remove packages that were installed automatically to satisfy dependencies
+.TP
+\fB\-t <\fIdirectory\fP>, \--tmp-dir <\fIdirectory\fP>\fR
+Specify \fIdirectory\fP as temporary directory
+.
+.SH "REPORTING BUGS"
+Report bugs to http://code.google.com/p/opkg/issues/list
+.
+.P
+Copyright \(co Opkg development team.
+.P
+Copyright \(co Ipkg development team.
+.
diff --git a/src/man/.svn/text-base/opkg-key.1.in.svn-base b/src/man/.svn/text-base/opkg-key.1.in.svn-base
new file mode 100644
index 0000000..f1aa221
--- /dev/null
+++ b/src/man/.svn/text-base/opkg-key.1.in.svn-base
@@ -0,0 +1,37 @@
+.TH "@PACKAGE_NAME@" 1 "@CLEAN_DATE@" "@PACKAGE_STRING@" "User Commands"
+.SH NAME
+opkg-key \- utility to manage opkg's list of trusted keys
+
+.
+.SH SYNOPSIS
+.B \fBopkg-key\fP [\fIOPTIONS...\fP] \fIsub-command\fP [\fIARGUMENTS...\fP]
+.
+.SH DESCRIPTION
+\fBopkg-key\fP is a utility to manage opkg's list of trusted keys. Opkg
+is a lightweight package management system based on Ipkg.
+.
+.SH SUB-COMMANDS
+.TP
+\fBadd <\fIfile\fP>\fR
+add the key contained in \fIfile\fP ('\-' for stdin)
+.TP
+\fBdel <\fIkeyid\fP>\fR
+remove the key \fIkeyid\fP
+.TP
+\fBlist\fR
+list trusted keys
+.
+.SH OPTIONS
+.TP
+\fB\-o <\fIroot\fP>\fR
+use \fIroot\fP as the offline root directory
+.
+.SH "REPORTING BUGS"
+Report bugs to http://code.google.com/p/opkg/issues/list
+.
+.SH COPYRIGHT
+.P
+Copyright \(co Opkg development team.
+.P
+Copyright \(co Ipkg development team.
+.
diff --git a/src/man/Makefile.am b/src/man/Makefile.am
new file mode 100644
index 0000000..6d0a535
--- /dev/null
+++ b/src/man/Makefile.am
@@ -0,0 +1,2 @@
+man_MANS=opkg-cl.1 \
+ opkg-key.1
diff --git a/src/man/opkg-cl.1.in b/src/man/opkg-cl.1.in
new file mode 100644
index 0000000..2bfb792
--- /dev/null
+++ b/src/man/opkg-cl.1.in
@@ -0,0 +1,190 @@
+.TH "@PACKAGE_NAME@" 1 "@CLEAN_DATE@" "@PACKAGE_STRING@" "User Commands"
+.SH NAME
+opkg-cl \- command line utility to install, upgrade and uninstall opkg
+software packages
+.
+.SH SYNOPSIS
+.B \fBopkg-cl\fP [\fIOPTIONS...\fP] \fIsub-command\fP [\fIARGUMENTS...\fP]
+.
+.SH DESCRIPTION
+\fBopkg-cl\fP is a simple utility to install, upgrade and uninstall opkg
+software packages. Opkg is a lightweight package management system based
+on Ipkg.
+.
+.SH "OPTIONS AND COMMANDS"
+.SS SUB-COMMANDS : PACKAGE MANIPULATION
+.TP
+\fBupdate\fR
+Update list of available packages
+.TP
+\fBupgrade\fR
+Upgrade installed packages
+.TP
+\fBinstall <\fIpackage(s)\fP>\fR
+Install \fIpackage(s)\fP
+.TP
+\fBconfigure <\fIpackage(s)\fP>\fR
+Configure unpacked \fIpackage(s)\fP
+.TP
+\fBremove <\fIpackages\fP|\fIregexp\fP>\fR
+Remove \fIpackage(s)\fP. \fIregexp\fP could be something like 'pkgname*' '*file*' or similar
+.TP
+\fBflag <\fIflag\fP> <\fIpackages\fP>\fR
+Flag \fIpackage(s)\fP. Available flags (one per invocation):
+.TS
+tab(@);
+l.
+hold
+noprune
+user
+ok
+installed
+unpacked
+.TE
+.SS INFORMATIONAL SUB-COMMANDS
+.TP
+\fBlist\fR
+List available packages
+.TP
+\fBlist-installed\fR
+List installed packages
+.TP
+\fBlist-upgradable\fR
+List installed and upgradable packages
+.TP
+\fBlist-changed-conffiles\fR
+List package configuration files which have been modified after installation
+.TP
+\fBfiles <\fIpackage\fP>\fR
+List files belonging to \fIpackage\fP
+.TP
+\fBsearch <\fIfile\fP|\fIregexp\fP>\fR
+List package providing \fIfile\fP
+.TP
+\fBinfo [\fIpackage\fP|\fIregexp\fP]\fR
+Display all info for selected packages
+.TP
+\fBstatus [\fIpackage\fP|\fIregexp\fP]\fR
+Display all statuses for selected packages
+.TP
+\fBdownload <\fIpackage\fP>\fR
+Download \fIpackage\fP to current directory
+.TP
+\fBcompare-version <\fIversion1\fP> <\fIoperator\fP> <\fIversion2\fP>\fR
+compare versions using following operators :
+.TS
+tab(@);
+c l.
+<<@less than
+<@less than or equal to
+<=@less than or equal to
+ =@equal to
+>=@greater than or equal to
+>@greater than or equal to
+>>@greater than
+.TE
+.TP
+\fBprint-architecture\fR
+List installable package architectures
+.TP
+\fBwhatdepends [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+.TP
+\fBwhatdependsrec [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+.TP
+\fBwhatprovides [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+.TP
+\fBwhatconflicts [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+.TP
+\fBwhatreplaces [\fI\-A\fP] <\fIpackage(s)\fP|\fIregexp\fP>\fR
+
+.SS OPTIONS
+.TP
+\fB\-A\fR
+Query all packages not just those installed
+.
+.TP
+\fB\-v <\fIlevel\fP>, --verbosity <\fIlevel\fP>\fR
+Set verbosity level to \fIlevel\fP. Verbosity levels :
+.TS
+tab(@);
+l l.
+0@errors only
+1@normal messages (default)
+2@informative messages
+3@debug
+4@debug level 2
+.TE
+.
+.TP
+\fB\-f <\fIconf_file\fP>, \fB\--conf <\fIconf_file\fP>\fR
+Use \fIconf_file\fP as the opkg configuration file
+.TP
+\fB\--cache <\fIdirectory\fP>\fR
+Use a package cache
+.TP
+\fB\-d <\fIdest_name\fP>, \fB\--dest <\fIdest_name\fP>\fR
+Use \fIdest_name\fP as the the root directory for
+package installation, removal, upgrading. \fIdest_name\fP should be a
+defined dest name from the configuration file, (but can also be a
+directory name in a pinch).
+.TP
+\fB\-o <\fIdirectory\fP>, \fB\--offline-root <\fIdirectory\fP>\fR
+Use \fIdirectory\fP as the root directory for offline installation of
+packages.
+.TP
+\fB\--add-dest <\fIname\fP>:<\fIpath\fP>\fR
+Register \fIpath\fP as installation target \fIname\fP for use in
+conjunction with \fB\--dest\fP
+.TP
+\fB\--add-arch <\fIarch\fP>:<\fIprio\fP>\fR
+Register the package architecture \fIarch\fP with the numeric
+priority \fIprio\fP. Lower priorities take precedence.
+.SS FORCE OPTIONS
+.TP
+\fB\--force-depends \fR
+Install/remove despite failed dependencies
+.TP
+\fB\--force-maintainer \fR
+Overwrite preexisting config files
+.TP
+\fB\--force-reinstall \fR
+Reinstall package(s)
+.TP
+\fB\--force-overwrite\fR
+Overwrite files from other package(s)
+.TP
+\fB\--force-downgrade\fR
+Allow opkg-cl to downgrade packages
+.TP
+\fB\--force-space \fR
+Disable free space checks
+.TP
+\fB\--force-postinstall \fR
+Execute package postinstall scripts in offline installation mode
+.TP
+\fB\--noaction\fR
+No action \- test only
+.TP
+\fB\--download-only\fR
+No action \- download only
+.TP
+\fB\--nodeps\fR
+Do not follow dependencies
+.TP
+\fB\--force-removal-of-dependent-packages\fR
+Remove package and all dependencies
+.TP
+\fB\--autoremove\fR
+Remove packages that were installed automatically to satisfy dependencies
+.TP
+\fB\-t <\fIdirectory\fP>, \--tmp-dir <\fIdirectory\fP>\fR
+Specify \fIdirectory\fP as temporary directory
+.
+.SH "REPORTING BUGS"
+Report bugs to http://code.google.com/p/opkg/issues/list
+.
+.P
+Copyright \(co Opkg development team.
+.P
+Copyright \(co Ipkg development team.
+.
diff --git a/src/man/opkg-key.1.in b/src/man/opkg-key.1.in
new file mode 100644
index 0000000..f1aa221
--- /dev/null
+++ b/src/man/opkg-key.1.in
@@ -0,0 +1,37 @@
+.TH "@PACKAGE_NAME@" 1 "@CLEAN_DATE@" "@PACKAGE_STRING@" "User Commands"
+.SH NAME
+opkg-key \- utility to manage opkg's list of trusted keys
+
+.
+.SH SYNOPSIS
+.B \fBopkg-key\fP [\fIOPTIONS...\fP] \fIsub-command\fP [\fIARGUMENTS...\fP]
+.
+.SH DESCRIPTION
+\fBopkg-key\fP is a utility to manage opkg's list of trusted keys. Opkg
+is a lightweight package management system based on Ipkg.
+.
+.SH SUB-COMMANDS
+.TP
+\fBadd <\fIfile\fP>\fR
+add the key contained in \fIfile\fP ('\-' for stdin)
+.TP
+\fBdel <\fIkeyid\fP>\fR
+remove the key \fIkeyid\fP
+.TP
+\fBlist\fR
+list trusted keys
+.
+.SH OPTIONS
+.TP
+\fB\-o <\fIroot\fP>\fR
+use \fIroot\fP as the offline root directory
+.
+.SH "REPORTING BUGS"
+Report bugs to http://code.google.com/p/opkg/issues/list
+.
+.SH COPYRIGHT
+.P
+Copyright \(co Opkg development team.
+.P
+Copyright \(co Ipkg development team.
+.
diff --git a/src/shave/.svn/all-wcprops b/src/shave/.svn/all-wcprops
new file mode 100644
index 0000000..7c3012c
--- /dev/null
+++ b/src/shave/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 29
+/svn/!svn/ver/364/trunk/shave
+END
+shave.m4
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svn/!svn/ver/364/trunk/shave/shave.m4
+END
+shave.in
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svn/!svn/ver/364/trunk/shave/shave.in
+END
+shave-libtool.in
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svn/!svn/ver/364/trunk/shave/shave-libtool.in
+END
diff --git a/src/shave/.svn/entries b/src/shave/.svn/entries
new file mode 100644
index 0000000..7d8d925
--- /dev/null
+++ b/src/shave/.svn/entries
@@ -0,0 +1,130 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/shave
+http://opkg.googlecode.com/svn
+
+
+
+2009-11-24T08:04:39.892985Z
+364
+pixdamix
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
+shave.m4
+file
+
+
+
+
+2012-02-03T08:11:57.403042Z
+c49f4d4afec388daa44eadb2ffd5a982
+2009-11-24T08:04:39.892985Z
+364
+pixdamix
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2236
+
+shave.in
+file
+
+
+
+
+2012-02-03T08:11:57.403042Z
+7eb781a1c62e37c9769add2ff8e28263
+2009-11-24T08:04:39.892985Z
+364
+pixdamix
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1180
+
+shave-libtool.in
+file
+
+
+
+
+2012-02-03T08:11:57.403042Z
+2c0a63426753c3876583d6838c671be4
+2009-11-24T08:04:39.892985Z
+364
+pixdamix
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1349
+
diff --git a/src/shave/.svn/text-base/shave-libtool.in.svn-base b/src/shave/.svn/text-base/shave-libtool.in.svn-base
new file mode 100644
index 0000000..1f3a720
--- /dev/null
+++ b/src/shave/.svn/text-base/shave-libtool.in.svn-base
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+# we need sed
+SED=@SED@
+if test -z "$SED" ; then
+SED=sed
+fi
+
+lt_unmangle ()
+{
+ last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
+}
+
+# the real libtool to use
+LIBTOOL="$1"
+shift
+
+# if 1, don't print anything, the underlaying wrapper will do it
+pass_though=0
+
+# scan the arguments, keep the right ones for libtool, and discover the mode
+preserved_args=
+while test "$#" -gt 0; do
+ opt="$1"
+ shift
+
+ case $opt in
+ --mode=*)
+ mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
+ preserved_args="$preserved_args $opt"
+ ;;
+ -o)
+ lt_output="$1"
+ preserved_args="$preserved_args $opt"
+ ;;
+ *)
+ preserved_args="$preserved_args $opt"
+ ;;
+ esac
+done
+
+case "$mode" in
+compile)
+ # shave will be called and print the actual CC/CXX/LINK line
+ preserved_args="$preserved_args --shave-mode=$mode"
+ pass_though=1
+ ;;
+link)
+ preserved_args="$preserved_args --shave-mode=$mode"
+ Q=" LINK "
+ ;;
+*)
+ # let's u
+ # echo "*** libtool: Unimplemented mode: $mode, fill a bug report"
+ ;;
+esac
+
+lt_unmangle "$lt_output"
+output=$last_result
+
+if test -z $V; then
+ if test $pass_though -eq 0; then
+ echo "$Q$output"
+ fi
+ $LIBTOOL --silent $preserved_args
+else
+ echo $LIBTOOL $preserved_args
+ $LIBTOOL $preserved_args
+fi
diff --git a/src/shave/.svn/text-base/shave.in.svn-base b/src/shave/.svn/text-base/shave.in.svn-base
new file mode 100644
index 0000000..5c16f27
--- /dev/null
+++ b/src/shave/.svn/text-base/shave.in.svn-base
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+# we need sed
+SED=@SED@
+if test -z "$SED" ; then
+SED=sed
+fi
+
+lt_unmangle ()
+{
+ last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
+}
+
+# the tool to wrap (cc, cxx, ar, ranlib, ..)
+tool="$1"
+shift
+
+# the reel tool (to call)
+REEL_TOOL="$1"
+shift
+
+pass_through=0
+preserved_args=
+while test "$#" -gt 0; do
+ opt="$1"
+ shift
+
+ case $opt in
+ --shave-mode=*)
+ mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
+ ;;
+ -o)
+ lt_output="$1"
+ preserved_args="$preserved_args $opt"
+ ;;
+ *)
+ preserved_args="$preserved_args $opt"
+ ;;
+ esac
+done
+
+# mode=link is handled in the libtool wrapper
+case "$mode,$tool" in
+link,*)
+ pass_through=1
+ ;;
+*,cxx)
+ Q=" CXX "
+ ;;
+*,cc)
+ Q=" CC "
+ ;;
+*,fc)
+ Q=" FC "
+ ;;
+*,f77)
+ Q=" F77 "
+ ;;
+*,objc)
+ Q=" OBJC "
+ ;;
+*,*)
+ # should not happen
+ Q=" CC "
+ ;;
+esac
+
+lt_unmangle "$lt_output"
+output=$last_result
+
+if test -z $V; then
+ if test $pass_through -eq 0; then
+ echo "$Q$output"
+ fi
+ $REEL_TOOL $preserved_args
+else
+ echo $REEL_TOOL $preserved_args
+ $REEL_TOOL $preserved_args
+fi
diff --git a/src/shave/.svn/text-base/shave.m4.svn-base b/src/shave/.svn/text-base/shave.m4.svn-base
new file mode 100644
index 0000000..0a3509e
--- /dev/null
+++ b/src/shave/.svn/text-base/shave.m4.svn-base
@@ -0,0 +1,77 @@
+dnl Make automake/libtool output more friendly to humans
+dnl Damien Lespiau <damien.lespiau@gmail.com>
+dnl
+dnl SHAVE_INIT([shavedir],[default_mode])
+dnl
+dnl shavedir: the directory where the shave scripts are, it defaults to
+dnl $(top_builddir)
+dnl default_mode: (enable|disable) default shave mode. This parameter
+dnl controls shave's behaviour when no option has been
+dnl given to configure. It defaults to disable.
+dnl
+dnl * SHAVE_INIT should be called late in your configure.(ac|in) file (just
+dnl before AC_CONFIG_FILE/AC_OUTPUT is perfect. This macro rewrites CC and
+dnl LIBTOOL, you don't want the configure tests to have these variables
+dnl re-defined.
+dnl * This macro requires GNU make's -s option.
+
+AC_DEFUN([_SHAVE_ARG_ENABLE],
+[
+ AC_ARG_ENABLE([shave],
+ AS_HELP_STRING(
+ [--enable-shave],
+ [use shave to make the build pretty [[default=$1]]]),,
+ [enable_shave=$1]
+ )
+])
+
+AC_DEFUN([SHAVE_INIT],
+[
+ dnl you can tweak the default value of enable_shave
+ m4_if([$2], [enable], [_SHAVE_ARG_ENABLE(yes)], [_SHAVE_ARG_ENABLE(no)])
+
+ if test x"$enable_shave" = xyes; then
+ dnl where can we find the shave scripts?
+ m4_if([$1],,
+ [shavedir="$ac_pwd"],
+ [shavedir="$ac_pwd/$1"])
+ AC_SUBST(shavedir)
+
+ dnl make is now quiet
+ AC_SUBST([MAKEFLAGS], [-s])
+ AC_SUBST([AM_MAKEFLAGS], ['`test -z $V && echo -s`'])
+
+ dnl we need sed
+ AC_CHECK_PROG(SED,sed,sed,false)
+
+ dnl substitute libtool
+ SHAVE_SAVED_LIBTOOL=$LIBTOOL
+ LIBTOOL="${SHELL} ${shavedir}/shave-libtool '${SHAVE_SAVED_LIBTOOL}'"
+ AC_SUBST(LIBTOOL)
+
+ dnl substitute cc/cxx
+ SHAVE_SAVED_CC=$CC
+ SHAVE_SAVED_CXX=$CXX
+ SHAVE_SAVED_FC=$FC
+ SHAVE_SAVED_F77=$F77
+ SHAVE_SAVED_OBJC=$OBJC
+ CC="${SHELL} ${shavedir}/shave cc ${SHAVE_SAVED_CC}"
+ CXX="${SHELL} ${shavedir}/shave cxx ${SHAVE_SAVED_CXX}"
+ FC="${SHELL} ${shavedir}/shave fc ${SHAVE_SAVED_FC}"
+ F77="${SHELL} ${shavedir}/shave f77 ${SHAVE_SAVED_F77}"
+ OBJC="${SHELL} ${shavedir}/shave objc ${SHAVE_SAVED_OBJC}"
+ AC_SUBST(CC)
+ AC_SUBST(CXX)
+ AC_SUBST(FC)
+ AC_SUBST(F77)
+ AC_SUBST(OBJC)
+
+ V=@
+ else
+ V=1
+ fi
+ Q='$(V:1=)'
+ AC_SUBST(V)
+ AC_SUBST(Q)
+])
+
diff --git a/src/shave/shave-libtool.in b/src/shave/shave-libtool.in
new file mode 100644
index 0000000..1f3a720
--- /dev/null
+++ b/src/shave/shave-libtool.in
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+# we need sed
+SED=@SED@
+if test -z "$SED" ; then
+SED=sed
+fi
+
+lt_unmangle ()
+{
+ last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
+}
+
+# the real libtool to use
+LIBTOOL="$1"
+shift
+
+# if 1, don't print anything, the underlaying wrapper will do it
+pass_though=0
+
+# scan the arguments, keep the right ones for libtool, and discover the mode
+preserved_args=
+while test "$#" -gt 0; do
+ opt="$1"
+ shift
+
+ case $opt in
+ --mode=*)
+ mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
+ preserved_args="$preserved_args $opt"
+ ;;
+ -o)
+ lt_output="$1"
+ preserved_args="$preserved_args $opt"
+ ;;
+ *)
+ preserved_args="$preserved_args $opt"
+ ;;
+ esac
+done
+
+case "$mode" in
+compile)
+ # shave will be called and print the actual CC/CXX/LINK line
+ preserved_args="$preserved_args --shave-mode=$mode"
+ pass_though=1
+ ;;
+link)
+ preserved_args="$preserved_args --shave-mode=$mode"
+ Q=" LINK "
+ ;;
+*)
+ # let's u
+ # echo "*** libtool: Unimplemented mode: $mode, fill a bug report"
+ ;;
+esac
+
+lt_unmangle "$lt_output"
+output=$last_result
+
+if test -z $V; then
+ if test $pass_though -eq 0; then
+ echo "$Q$output"
+ fi
+ $LIBTOOL --silent $preserved_args
+else
+ echo $LIBTOOL $preserved_args
+ $LIBTOOL $preserved_args
+fi
diff --git a/src/shave/shave.in b/src/shave/shave.in
new file mode 100644
index 0000000..5c16f27
--- /dev/null
+++ b/src/shave/shave.in
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+# we need sed
+SED=@SED@
+if test -z "$SED" ; then
+SED=sed
+fi
+
+lt_unmangle ()
+{
+ last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
+}
+
+# the tool to wrap (cc, cxx, ar, ranlib, ..)
+tool="$1"
+shift
+
+# the reel tool (to call)
+REEL_TOOL="$1"
+shift
+
+pass_through=0
+preserved_args=
+while test "$#" -gt 0; do
+ opt="$1"
+ shift
+
+ case $opt in
+ --shave-mode=*)
+ mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
+ ;;
+ -o)
+ lt_output="$1"
+ preserved_args="$preserved_args $opt"
+ ;;
+ *)
+ preserved_args="$preserved_args $opt"
+ ;;
+ esac
+done
+
+# mode=link is handled in the libtool wrapper
+case "$mode,$tool" in
+link,*)
+ pass_through=1
+ ;;
+*,cxx)
+ Q=" CXX "
+ ;;
+*,cc)
+ Q=" CC "
+ ;;
+*,fc)
+ Q=" FC "
+ ;;
+*,f77)
+ Q=" F77 "
+ ;;
+*,objc)
+ Q=" OBJC "
+ ;;
+*,*)
+ # should not happen
+ Q=" CC "
+ ;;
+esac
+
+lt_unmangle "$lt_output"
+output=$last_result
+
+if test -z $V; then
+ if test $pass_through -eq 0; then
+ echo "$Q$output"
+ fi
+ $REEL_TOOL $preserved_args
+else
+ echo $REEL_TOOL $preserved_args
+ $REEL_TOOL $preserved_args
+fi
diff --git a/src/shave/shave.m4 b/src/shave/shave.m4
new file mode 100644
index 0000000..0a3509e
--- /dev/null
+++ b/src/shave/shave.m4
@@ -0,0 +1,77 @@
+dnl Make automake/libtool output more friendly to humans
+dnl Damien Lespiau <damien.lespiau@gmail.com>
+dnl
+dnl SHAVE_INIT([shavedir],[default_mode])
+dnl
+dnl shavedir: the directory where the shave scripts are, it defaults to
+dnl $(top_builddir)
+dnl default_mode: (enable|disable) default shave mode. This parameter
+dnl controls shave's behaviour when no option has been
+dnl given to configure. It defaults to disable.
+dnl
+dnl * SHAVE_INIT should be called late in your configure.(ac|in) file (just
+dnl before AC_CONFIG_FILE/AC_OUTPUT is perfect. This macro rewrites CC and
+dnl LIBTOOL, you don't want the configure tests to have these variables
+dnl re-defined.
+dnl * This macro requires GNU make's -s option.
+
+AC_DEFUN([_SHAVE_ARG_ENABLE],
+[
+ AC_ARG_ENABLE([shave],
+ AS_HELP_STRING(
+ [--enable-shave],
+ [use shave to make the build pretty [[default=$1]]]),,
+ [enable_shave=$1]
+ )
+])
+
+AC_DEFUN([SHAVE_INIT],
+[
+ dnl you can tweak the default value of enable_shave
+ m4_if([$2], [enable], [_SHAVE_ARG_ENABLE(yes)], [_SHAVE_ARG_ENABLE(no)])
+
+ if test x"$enable_shave" = xyes; then
+ dnl where can we find the shave scripts?
+ m4_if([$1],,
+ [shavedir="$ac_pwd"],
+ [shavedir="$ac_pwd/$1"])
+ AC_SUBST(shavedir)
+
+ dnl make is now quiet
+ AC_SUBST([MAKEFLAGS], [-s])
+ AC_SUBST([AM_MAKEFLAGS], ['`test -z $V && echo -s`'])
+
+ dnl we need sed
+ AC_CHECK_PROG(SED,sed,sed,false)
+
+ dnl substitute libtool
+ SHAVE_SAVED_LIBTOOL=$LIBTOOL
+ LIBTOOL="${SHELL} ${shavedir}/shave-libtool '${SHAVE_SAVED_LIBTOOL}'"
+ AC_SUBST(LIBTOOL)
+
+ dnl substitute cc/cxx
+ SHAVE_SAVED_CC=$CC
+ SHAVE_SAVED_CXX=$CXX
+ SHAVE_SAVED_FC=$FC
+ SHAVE_SAVED_F77=$F77
+ SHAVE_SAVED_OBJC=$OBJC
+ CC="${SHELL} ${shavedir}/shave cc ${SHAVE_SAVED_CC}"
+ CXX="${SHELL} ${shavedir}/shave cxx ${SHAVE_SAVED_CXX}"
+ FC="${SHELL} ${shavedir}/shave fc ${SHAVE_SAVED_FC}"
+ F77="${SHELL} ${shavedir}/shave f77 ${SHAVE_SAVED_F77}"
+ OBJC="${SHELL} ${shavedir}/shave objc ${SHAVE_SAVED_OBJC}"
+ AC_SUBST(CC)
+ AC_SUBST(CXX)
+ AC_SUBST(FC)
+ AC_SUBST(F77)
+ AC_SUBST(OBJC)
+
+ V=@
+ else
+ V=1
+ fi
+ Q='$(V:1=)'
+ AC_SUBST(V)
+ AC_SUBST(Q)
+])
+
diff --git a/src/src/.svn/all-wcprops b/src/src/.svn/all-wcprops
new file mode 100644
index 0000000..2fab829
--- /dev/null
+++ b/src/src/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 27
+/svn/!svn/ver/606/trunk/src
+END
+Makefile.am
+K 25
+svn:wc:ra_dav:version-url
+V 39
+/svn/!svn/ver/499/trunk/src/Makefile.am
+END
+opkg-cl.c
+K 25
+svn:wc:ra_dav:version-url
+V 37
+/svn/!svn/ver/606/trunk/src/opkg-cl.c
+END
diff --git a/src/src/.svn/entries b/src/src/.svn/entries
new file mode 100644
index 0000000..6954347
--- /dev/null
+++ b/src/src/.svn/entries
@@ -0,0 +1,96 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/src
+http://opkg.googlecode.com/svn
+
+
+
+2011-02-21T04:24:55.981276Z
+606
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
+Makefile.am
+file
+
+
+
+
+2012-02-03T08:11:57.135042Z
+ece988fbb1377903665cb98ff19853b4
+2009-12-18T00:46:30.184915Z
+499
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+203
+
+opkg-cl.c
+file
+
+
+
+
+2012-02-03T08:11:57.135042Z
+5185597dadd48ee6b6032c3d53d84078
+2011-02-21T04:24:55.981276Z
+606
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12085
+
diff --git a/src/src/.svn/text-base/Makefile.am.svn-base b/src/src/.svn/text-base/Makefile.am.svn-base
new file mode 100644
index 0000000..efdc19d
--- /dev/null
+++ b/src/src/.svn/text-base/Makefile.am.svn-base
@@ -0,0 +1,6 @@
+AM_CFLAGS = -I${top_srcdir}/libopkg ${ALL_CFLAGS}
+bin_PROGRAMS = opkg-cl
+
+opkg_cl_SOURCES = opkg-cl.c
+opkg_cl_LDADD = $(top_builddir)/libopkg/libopkg.la \
+ $(top_builddir)/libbb/libbb.la
diff --git a/src/src/.svn/text-base/opkg-cl.c.svn-base b/src/src/.svn/text-base/opkg-cl.c.svn-base
new file mode 100644
index 0000000..1b927e5
--- /dev/null
+++ b/src/src/.svn/text-base/opkg-cl.c.svn-base
@@ -0,0 +1,390 @@
+/* opkg-cl.c - the opkg package management system
+
+ Florian Boor
+ Copyright (C) 2003 kernel concepts
+
+ Carl D. Worth
+ Copyright 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.
+
+ opkg command line frontend using libopkg
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <getopt.h>
+
+#include "opkg_conf.h"
+#include "opkg_cmd.h"
+#include "file_util.h"
+#include "opkg_message.h"
+#include "opkg_download.h"
+#include "../libbb/libbb.h"
+
+enum {
+ ARGS_OPT_FORCE_MAINTAINER = 129,
+ ARGS_OPT_FORCE_DEPENDS,
+ ARGS_OPT_FORCE_OVERWRITE,
+ ARGS_OPT_FORCE_DOWNGRADE,
+ ARGS_OPT_FORCE_REINSTALL,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES,
+ ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES,
+ ARGS_OPT_FORCE_SPACE,
+ ARGS_OPT_FORCE_POSTINSTALL,
+ ARGS_OPT_FORCE_REMOVE,
+ ARGS_OPT_ADD_ARCH,
+ ARGS_OPT_ADD_DEST,
+ ARGS_OPT_NOACTION,
+ ARGS_OPT_DOWNLOAD_ONLY,
+ ARGS_OPT_NODEPS,
+ ARGS_OPT_AUTOREMOVE,
+ ARGS_OPT_CACHE,
+};
+
+static struct option long_options[] = {
+ {"query-all", 0, 0, 'A'},
+ {"autoremove", 0, 0, ARGS_OPT_AUTOREMOVE},
+ {"cache", 1, 0, ARGS_OPT_CACHE},
+ {"conf-file", 1, 0, 'f'},
+ {"conf", 1, 0, 'f'},
+ {"dest", 1, 0, 'd'},
+ {"force-maintainer", 0, 0, ARGS_OPT_FORCE_MAINTAINER},
+ {"force_maintainer", 0, 0, ARGS_OPT_FORCE_MAINTAINER},
+ {"force-depends", 0, 0, ARGS_OPT_FORCE_DEPENDS},
+ {"force_depends", 0, 0, ARGS_OPT_FORCE_DEPENDS},
+ {"force-overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE},
+ {"force_overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE},
+ {"force_downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE},
+ {"force-downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE},
+ {"force-reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL},
+ {"force_reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL},
+ {"force-space", 0, 0, ARGS_OPT_FORCE_SPACE},
+ {"force_space", 0, 0, ARGS_OPT_FORCE_SPACE},
+ {"recursive", 0, 0, ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES},
+ {"force-removal-of-dependent-packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES},
+ {"force_removal_of_dependent_packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES},
+ {"force-removal-of-essential-packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES},
+ {"force_removal_of_essential_packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES},
+ {"force-postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL},
+ {"force_postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL},
+ {"force-remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
+ {"force_remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
+ {"noaction", 0, 0, ARGS_OPT_NOACTION},
+ {"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY},
+ {"nodeps", 0, 0, ARGS_OPT_NODEPS},
+ {"offline", 1, 0, 'o'},
+ {"offline-root", 1, 0, 'o'},
+ {"add-arch", 1, 0, ARGS_OPT_ADD_ARCH},
+ {"add-dest", 1, 0, ARGS_OPT_ADD_DEST},
+ {"test", 0, 0, ARGS_OPT_NOACTION},
+ {"tmp-dir", 1, 0, 't'},
+ {"tmp_dir", 1, 0, 't'},
+ {"verbosity", 2, 0, 'V'},
+ {"version", 0, 0, 'v'},
+ {0, 0, 0, 0}
+};
+
+static int
+args_parse(int argc, char *argv[])
+{
+ int c;
+ int option_index = 0;
+ int parse_err = 0;
+ char *tuple, *targ;
+
+ while (1) {
+ c = getopt_long_only(argc, argv, "Ad:f:no:p:t:vV::",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'A':
+ conf->query_all = 1;
+ break;
+ case 'd':
+ conf->dest_str = xstrdup(optarg);
+ break;
+ case 'f':
+ conf->conf_file = xstrdup(optarg);
+ break;
+ case 'o':
+ conf->offline_root = xstrdup(optarg);
+ break;
+ case 't':
+ conf->tmp_dir = xstrdup(optarg);
+ break;
+ case 'v':
+ printf("opkg version %s\n", VERSION);
+ exit(0);
+ case 'V':
+ conf->verbosity = INFO;
+ if (optarg != NULL)
+ conf->verbosity = atoi(optarg);
+ break;
+ case ARGS_OPT_AUTOREMOVE:
+ conf->autoremove = 1;
+ break;
+ case ARGS_OPT_CACHE:
+ free(conf->cache);
+ conf->cache = xstrdup(optarg);
+ break;
+ case ARGS_OPT_FORCE_MAINTAINER:
+ conf->force_maintainer = 1;
+ break;
+ case ARGS_OPT_FORCE_DEPENDS:
+ conf->force_depends = 1;
+ break;
+ case ARGS_OPT_FORCE_OVERWRITE:
+ conf->force_overwrite = 1;
+ break;
+ case ARGS_OPT_FORCE_DOWNGRADE:
+ conf->force_downgrade = 1;
+ break;
+ case ARGS_OPT_FORCE_REINSTALL:
+ conf->force_reinstall = 1;
+ break;
+ case ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES:
+ conf->force_removal_of_essential_packages = 1;
+ break;
+ case ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES:
+ conf->force_removal_of_dependent_packages = 1;
+ break;
+ case ARGS_OPT_FORCE_SPACE:
+ conf->force_space = 1;
+ break;
+ case ARGS_OPT_FORCE_POSTINSTALL:
+ conf->force_postinstall = 1;
+ break;
+ case ARGS_OPT_FORCE_REMOVE:
+ conf->force_remove = 1;
+ break;
+ case ARGS_OPT_NODEPS:
+ conf->nodeps = 1;
+ break;
+ case ARGS_OPT_ADD_ARCH:
+ case ARGS_OPT_ADD_DEST:
+ tuple = xstrdup(optarg);
+ if ((targ = strchr(tuple, ':')) != NULL) {
+ *targ++ = 0;
+ if ((strlen(tuple) > 0) && (strlen(targ) > 0)) {
+ nv_pair_list_append(
+ (c == ARGS_OPT_ADD_ARCH)
+ ? &conf->arch_list : &conf->tmp_dest_list,
+ tuple, targ);
+ }
+ }
+ free(tuple);
+ break;
+ case ARGS_OPT_NOACTION:
+ conf->noaction = 1;
+ break;
+ case ARGS_OPT_DOWNLOAD_ONLY:
+ conf->download_only = 1;
+ break;
+ case ':':
+ parse_err = -1;
+ break;
+ case '?':
+ parse_err = -1;
+ break;
+ default:
+ printf("Confusion: getopt_long returned %d\n", c);
+ }
+ }
+
+ if (parse_err)
+ return parse_err;
+ else
+ return optind;
+}
+
+static void
+usage()
+{
+ printf("usage: opkg [options...] sub-command [arguments...]\n");
+ printf("where sub-command is one of:\n");
+
+ printf("\nPackage Manipulation:\n");
+ printf("\tupdate Update list of available packages\n");
+ printf("\tupgrade Upgrade installed packages\n");
+ printf("\tinstall <pkgs> Install package(s)\n");
+ printf("\tconfigure <pkgs> Configure unpacked package(s)\n");
+ printf("\tremove <pkgs|regexp> Remove package(s)\n");
+ printf("\tflag <flag> <pkgs> Flag package(s)\n");
+ printf("\t <flag>=hold|noprune|user|ok|installed|unpacked (one per invocation)\n");
+
+ printf("\nInformational Commands:\n");
+ printf("\tlist List available packages\n");
+ printf("\tlist-installed List installed packages\n");
+ printf("\tlist-upgradable List installed and upgradable packages\n");
+ printf("\tlist-changed-conffiles List user modified configuration files\n");
+ printf("\tfiles <pkg> List files belonging to <pkg>\n");
+ printf("\tsearch <file|regexp> List package providing <file>\n");
+ printf("\tinfo [pkg|regexp] Display all info for <pkg>\n");
+ printf("\tstatus [pkg|regexp] Display all status for <pkg>\n");
+ printf("\tdownload <pkg> Download <pkg> to current directory\n");
+ printf("\tcompare-versions <v1> <op> <v2>\n");
+ printf("\t compare versions using <= < > >= = << >>\n");
+ printf("\tprint-architecture List installable package architectures\n");
+ printf("\tdepends [-A] [pkgname|pat]+\n");
+ printf("\twhatdepends [-A] [pkgname|pat]+\n");
+ printf("\twhatdependsrec [-A] [pkgname|pat]+\n");
+ printf("\twhatrecommends[-A] [pkgname|pat]+\n");
+ printf("\twhatsuggests[-A] [pkgname|pat]+\n");
+ printf("\twhatprovides [-A] [pkgname|pat]+\n");
+ printf("\twhatconflicts [-A] [pkgname|pat]+\n");
+ printf("\twhatreplaces [-A] [pkgname|pat]+\n");
+
+ printf("\nOptions:\n");
+ printf("\t-A Query all packages not just those installed\n");
+ printf("\t-V[<level>] Set verbosity level to <level>.\n");
+ printf("\t--verbosity[=<level>] Verbosity levels:\n");
+ printf("\t 0 errors only\n");
+ printf("\t 1 normal messages (default)\n");
+ printf("\t 2 informative messages\n");
+ printf("\t 3 debug\n");
+ printf("\t 4 debug level 2\n");
+ printf("\t-f <conf_file> Use <conf_file> as the opkg configuration file\n");
+ printf("\t--conf <conf_file>\n");
+ printf("\t--cache <directory> Use a package cache\n");
+ printf("\t-d <dest_name> Use <dest_name> as the the root directory for\n");
+ printf("\t--dest <dest_name> package installation, removal, upgrading.\n");
+ printf(" <dest_name> should be a defined dest name from\n");
+ printf(" the configuration file, (but can also be a\n");
+ printf(" directory name in a pinch).\n");
+ printf("\t-o <dir> Use <dir> as the root directory for\n");
+ printf("\t--offline-root <dir> offline installation of packages.\n");
+ printf("\t--add-arch <arch>:<prio> Register architecture with given priority\n");
+ printf("\t--add-dest <name>:<path> Register destination with given path\n");
+
+ printf("\nForce Options:\n");
+ printf("\t--force-depends Install/remove despite failed dependencies\n");
+ printf("\t--force-maintainer Overwrite preexisting config files\n");
+ printf("\t--force-reinstall Reinstall package(s)\n");
+ printf("\t--force-overwrite Overwrite files from other package(s)\n");
+ printf("\t--force-downgrade Allow opkg to downgrade packages\n");
+ printf("\t--force-space Disable free space checks\n");
+ printf("\t--force-postinstall Run postinstall scripts even in offline mode\n");
+ printf("\t--force-remove Remove package even if prerm script fails\n");
+ printf("\t--noaction No action -- test only\n");
+ printf("\t--download-only No action -- download only\n");
+ printf("\t--nodeps Do not follow dependencies\n");
+ printf("\t--force-removal-of-dependent-packages\n");
+ printf("\t Remove package and all dependencies\n");
+ printf("\t--autoremove Remove packages that were installed\n");
+ printf("\t automatically to satisfy dependencies\n");
+ printf("\t-t Specify tmp-dir.\n");
+ printf("\t--tmp-dir Specify tmp-dir.\n");
+
+ printf("\n");
+
+ printf(" regexp could be something like 'pkgname*' '*file*' or similar\n");
+ printf(" e.g. opkg info 'libstd*' or opkg search '*libop*' or opkg remove 'libncur*'\n");
+
+ /* --force-removal-of-essential-packages Let opkg remove essential packages.
+ Using this option is almost guaranteed to break your system, hence this option
+ is not even advertised in the usage statement. */
+
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opts, err = -1;
+ char *cmd_name;
+ opkg_cmd_t *cmd;
+ int nocheckfordirorfile = 0;
+ int noreadfeedsfile = 0;
+
+ if (opkg_conf_init())
+ goto err0;
+
+ conf->verbosity = NOTICE;
+
+ opts = args_parse(argc, argv);
+ if (opts == argc || opts < 0) {
+ fprintf(stderr, "opkg must have one sub-command argument\n");
+ usage();
+ }
+
+ cmd_name = argv[opts++];
+
+ if (!strcmp(cmd_name,"print-architecture") ||
+ !strcmp(cmd_name,"print_architecture") ||
+ !strcmp(cmd_name,"print-installation-architecture") ||
+ !strcmp(cmd_name,"print_installation_architecture") )
+ nocheckfordirorfile = 1;
+
+ if (!strcmp(cmd_name,"flag") ||
+ !strcmp(cmd_name,"configure") ||
+ !strcmp(cmd_name,"remove") ||
+ !strcmp(cmd_name,"files") ||
+ !strcmp(cmd_name,"search") ||
+ !strcmp(cmd_name,"compare_versions") ||
+ !strcmp(cmd_name,"compare-versions") ||
+ !strcmp(cmd_name,"list_installed") ||
+ !strcmp(cmd_name,"list-installed") ||
+ !strcmp(cmd_name,"list_changed_conffiles") ||
+ !strcmp(cmd_name,"list-changed-conffiles") ||
+ !strcmp(cmd_name,"status") )
+ noreadfeedsfile = 1;
+
+ cmd = opkg_cmd_find(cmd_name);
+ if (cmd == NULL) {
+ fprintf(stderr, "%s: unknown sub-command %s\n", argv[0],
+ cmd_name);
+ usage();
+ }
+
+ conf->pfm = cmd->pfm;
+
+ if (opkg_conf_load())
+ goto err0;
+
+ if (!nocheckfordirorfile) {
+ if (!noreadfeedsfile) {
+ if (pkg_hash_load_feeds())
+ goto err1;
+ }
+
+ if (pkg_hash_load_status_files())
+ goto err1;
+ }
+
+ if (cmd->requires_args && opts == argc) {
+ fprintf(stderr,
+ "%s: the ``%s'' command requires at least one argument\n",
+ argv[0], cmd_name);
+ usage();
+ }
+
+ err = opkg_cmd_exec(cmd, argc - opts, (const char **) (argv + opts));
+
+#ifdef HAVE_CURL
+ opkg_curl_cleanup();
+#endif
+err1:
+ opkg_conf_deinit();
+
+err0:
+ print_error_list();
+ free_error_list();
+
+ return err;
+}
diff --git a/src/src/Makefile.am b/src/src/Makefile.am
new file mode 100644
index 0000000..efdc19d
--- /dev/null
+++ b/src/src/Makefile.am
@@ -0,0 +1,6 @@
+AM_CFLAGS = -I${top_srcdir}/libopkg ${ALL_CFLAGS}
+bin_PROGRAMS = opkg-cl
+
+opkg_cl_SOURCES = opkg-cl.c
+opkg_cl_LDADD = $(top_builddir)/libopkg/libopkg.la \
+ $(top_builddir)/libbb/libbb.la
diff --git a/src/src/opkg-cl.c b/src/src/opkg-cl.c
new file mode 100644
index 0000000..1b927e5
--- /dev/null
+++ b/src/src/opkg-cl.c
@@ -0,0 +1,390 @@
+/* opkg-cl.c - the opkg package management system
+
+ Florian Boor
+ Copyright (C) 2003 kernel concepts
+
+ Carl D. Worth
+ Copyright 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.
+
+ opkg command line frontend using libopkg
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <getopt.h>
+
+#include "opkg_conf.h"
+#include "opkg_cmd.h"
+#include "file_util.h"
+#include "opkg_message.h"
+#include "opkg_download.h"
+#include "../libbb/libbb.h"
+
+enum {
+ ARGS_OPT_FORCE_MAINTAINER = 129,
+ ARGS_OPT_FORCE_DEPENDS,
+ ARGS_OPT_FORCE_OVERWRITE,
+ ARGS_OPT_FORCE_DOWNGRADE,
+ ARGS_OPT_FORCE_REINSTALL,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES,
+ ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES,
+ ARGS_OPT_FORCE_SPACE,
+ ARGS_OPT_FORCE_POSTINSTALL,
+ ARGS_OPT_FORCE_REMOVE,
+ ARGS_OPT_ADD_ARCH,
+ ARGS_OPT_ADD_DEST,
+ ARGS_OPT_NOACTION,
+ ARGS_OPT_DOWNLOAD_ONLY,
+ ARGS_OPT_NODEPS,
+ ARGS_OPT_AUTOREMOVE,
+ ARGS_OPT_CACHE,
+};
+
+static struct option long_options[] = {
+ {"query-all", 0, 0, 'A'},
+ {"autoremove", 0, 0, ARGS_OPT_AUTOREMOVE},
+ {"cache", 1, 0, ARGS_OPT_CACHE},
+ {"conf-file", 1, 0, 'f'},
+ {"conf", 1, 0, 'f'},
+ {"dest", 1, 0, 'd'},
+ {"force-maintainer", 0, 0, ARGS_OPT_FORCE_MAINTAINER},
+ {"force_maintainer", 0, 0, ARGS_OPT_FORCE_MAINTAINER},
+ {"force-depends", 0, 0, ARGS_OPT_FORCE_DEPENDS},
+ {"force_depends", 0, 0, ARGS_OPT_FORCE_DEPENDS},
+ {"force-overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE},
+ {"force_overwrite", 0, 0, ARGS_OPT_FORCE_OVERWRITE},
+ {"force_downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE},
+ {"force-downgrade", 0, 0, ARGS_OPT_FORCE_DOWNGRADE},
+ {"force-reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL},
+ {"force_reinstall", 0, 0, ARGS_OPT_FORCE_REINSTALL},
+ {"force-space", 0, 0, ARGS_OPT_FORCE_SPACE},
+ {"force_space", 0, 0, ARGS_OPT_FORCE_SPACE},
+ {"recursive", 0, 0, ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES},
+ {"force-removal-of-dependent-packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES},
+ {"force_removal_of_dependent_packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES},
+ {"force-removal-of-essential-packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES},
+ {"force_removal_of_essential_packages", 0, 0,
+ ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES},
+ {"force-postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL},
+ {"force_postinstall", 0, 0, ARGS_OPT_FORCE_POSTINSTALL},
+ {"force-remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
+ {"force_remove", 0, 0, ARGS_OPT_FORCE_REMOVE},
+ {"noaction", 0, 0, ARGS_OPT_NOACTION},
+ {"download-only", 0, 0, ARGS_OPT_DOWNLOAD_ONLY},
+ {"nodeps", 0, 0, ARGS_OPT_NODEPS},
+ {"offline", 1, 0, 'o'},
+ {"offline-root", 1, 0, 'o'},
+ {"add-arch", 1, 0, ARGS_OPT_ADD_ARCH},
+ {"add-dest", 1, 0, ARGS_OPT_ADD_DEST},
+ {"test", 0, 0, ARGS_OPT_NOACTION},
+ {"tmp-dir", 1, 0, 't'},
+ {"tmp_dir", 1, 0, 't'},
+ {"verbosity", 2, 0, 'V'},
+ {"version", 0, 0, 'v'},
+ {0, 0, 0, 0}
+};
+
+static int
+args_parse(int argc, char *argv[])
+{
+ int c;
+ int option_index = 0;
+ int parse_err = 0;
+ char *tuple, *targ;
+
+ while (1) {
+ c = getopt_long_only(argc, argv, "Ad:f:no:p:t:vV::",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'A':
+ conf->query_all = 1;
+ break;
+ case 'd':
+ conf->dest_str = xstrdup(optarg);
+ break;
+ case 'f':
+ conf->conf_file = xstrdup(optarg);
+ break;
+ case 'o':
+ conf->offline_root = xstrdup(optarg);
+ break;
+ case 't':
+ conf->tmp_dir = xstrdup(optarg);
+ break;
+ case 'v':
+ printf("opkg version %s\n", VERSION);
+ exit(0);
+ case 'V':
+ conf->verbosity = INFO;
+ if (optarg != NULL)
+ conf->verbosity = atoi(optarg);
+ break;
+ case ARGS_OPT_AUTOREMOVE:
+ conf->autoremove = 1;
+ break;
+ case ARGS_OPT_CACHE:
+ free(conf->cache);
+ conf->cache = xstrdup(optarg);
+ break;
+ case ARGS_OPT_FORCE_MAINTAINER:
+ conf->force_maintainer = 1;
+ break;
+ case ARGS_OPT_FORCE_DEPENDS:
+ conf->force_depends = 1;
+ break;
+ case ARGS_OPT_FORCE_OVERWRITE:
+ conf->force_overwrite = 1;
+ break;
+ case ARGS_OPT_FORCE_DOWNGRADE:
+ conf->force_downgrade = 1;
+ break;
+ case ARGS_OPT_FORCE_REINSTALL:
+ conf->force_reinstall = 1;
+ break;
+ case ARGS_OPT_FORCE_REMOVAL_OF_ESSENTIAL_PACKAGES:
+ conf->force_removal_of_essential_packages = 1;
+ break;
+ case ARGS_OPT_FORCE_REMOVAL_OF_DEPENDENT_PACKAGES:
+ conf->force_removal_of_dependent_packages = 1;
+ break;
+ case ARGS_OPT_FORCE_SPACE:
+ conf->force_space = 1;
+ break;
+ case ARGS_OPT_FORCE_POSTINSTALL:
+ conf->force_postinstall = 1;
+ break;
+ case ARGS_OPT_FORCE_REMOVE:
+ conf->force_remove = 1;
+ break;
+ case ARGS_OPT_NODEPS:
+ conf->nodeps = 1;
+ break;
+ case ARGS_OPT_ADD_ARCH:
+ case ARGS_OPT_ADD_DEST:
+ tuple = xstrdup(optarg);
+ if ((targ = strchr(tuple, ':')) != NULL) {
+ *targ++ = 0;
+ if ((strlen(tuple) > 0) && (strlen(targ) > 0)) {
+ nv_pair_list_append(
+ (c == ARGS_OPT_ADD_ARCH)
+ ? &conf->arch_list : &conf->tmp_dest_list,
+ tuple, targ);
+ }
+ }
+ free(tuple);
+ break;
+ case ARGS_OPT_NOACTION:
+ conf->noaction = 1;
+ break;
+ case ARGS_OPT_DOWNLOAD_ONLY:
+ conf->download_only = 1;
+ break;
+ case ':':
+ parse_err = -1;
+ break;
+ case '?':
+ parse_err = -1;
+ break;
+ default:
+ printf("Confusion: getopt_long returned %d\n", c);
+ }
+ }
+
+ if (parse_err)
+ return parse_err;
+ else
+ return optind;
+}
+
+static void
+usage()
+{
+ printf("usage: opkg [options...] sub-command [arguments...]\n");
+ printf("where sub-command is one of:\n");
+
+ printf("\nPackage Manipulation:\n");
+ printf("\tupdate Update list of available packages\n");
+ printf("\tupgrade Upgrade installed packages\n");
+ printf("\tinstall <pkgs> Install package(s)\n");
+ printf("\tconfigure <pkgs> Configure unpacked package(s)\n");
+ printf("\tremove <pkgs|regexp> Remove package(s)\n");
+ printf("\tflag <flag> <pkgs> Flag package(s)\n");
+ printf("\t <flag>=hold|noprune|user|ok|installed|unpacked (one per invocation)\n");
+
+ printf("\nInformational Commands:\n");
+ printf("\tlist List available packages\n");
+ printf("\tlist-installed List installed packages\n");
+ printf("\tlist-upgradable List installed and upgradable packages\n");
+ printf("\tlist-changed-conffiles List user modified configuration files\n");
+ printf("\tfiles <pkg> List files belonging to <pkg>\n");
+ printf("\tsearch <file|regexp> List package providing <file>\n");
+ printf("\tinfo [pkg|regexp] Display all info for <pkg>\n");
+ printf("\tstatus [pkg|regexp] Display all status for <pkg>\n");
+ printf("\tdownload <pkg> Download <pkg> to current directory\n");
+ printf("\tcompare-versions <v1> <op> <v2>\n");
+ printf("\t compare versions using <= < > >= = << >>\n");
+ printf("\tprint-architecture List installable package architectures\n");
+ printf("\tdepends [-A] [pkgname|pat]+\n");
+ printf("\twhatdepends [-A] [pkgname|pat]+\n");
+ printf("\twhatdependsrec [-A] [pkgname|pat]+\n");
+ printf("\twhatrecommends[-A] [pkgname|pat]+\n");
+ printf("\twhatsuggests[-A] [pkgname|pat]+\n");
+ printf("\twhatprovides [-A] [pkgname|pat]+\n");
+ printf("\twhatconflicts [-A] [pkgname|pat]+\n");
+ printf("\twhatreplaces [-A] [pkgname|pat]+\n");
+
+ printf("\nOptions:\n");
+ printf("\t-A Query all packages not just those installed\n");
+ printf("\t-V[<level>] Set verbosity level to <level>.\n");
+ printf("\t--verbosity[=<level>] Verbosity levels:\n");
+ printf("\t 0 errors only\n");
+ printf("\t 1 normal messages (default)\n");
+ printf("\t 2 informative messages\n");
+ printf("\t 3 debug\n");
+ printf("\t 4 debug level 2\n");
+ printf("\t-f <conf_file> Use <conf_file> as the opkg configuration file\n");
+ printf("\t--conf <conf_file>\n");
+ printf("\t--cache <directory> Use a package cache\n");
+ printf("\t-d <dest_name> Use <dest_name> as the the root directory for\n");
+ printf("\t--dest <dest_name> package installation, removal, upgrading.\n");
+ printf(" <dest_name> should be a defined dest name from\n");
+ printf(" the configuration file, (but can also be a\n");
+ printf(" directory name in a pinch).\n");
+ printf("\t-o <dir> Use <dir> as the root directory for\n");
+ printf("\t--offline-root <dir> offline installation of packages.\n");
+ printf("\t--add-arch <arch>:<prio> Register architecture with given priority\n");
+ printf("\t--add-dest <name>:<path> Register destination with given path\n");
+
+ printf("\nForce Options:\n");
+ printf("\t--force-depends Install/remove despite failed dependencies\n");
+ printf("\t--force-maintainer Overwrite preexisting config files\n");
+ printf("\t--force-reinstall Reinstall package(s)\n");
+ printf("\t--force-overwrite Overwrite files from other package(s)\n");
+ printf("\t--force-downgrade Allow opkg to downgrade packages\n");
+ printf("\t--force-space Disable free space checks\n");
+ printf("\t--force-postinstall Run postinstall scripts even in offline mode\n");
+ printf("\t--force-remove Remove package even if prerm script fails\n");
+ printf("\t--noaction No action -- test only\n");
+ printf("\t--download-only No action -- download only\n");
+ printf("\t--nodeps Do not follow dependencies\n");
+ printf("\t--force-removal-of-dependent-packages\n");
+ printf("\t Remove package and all dependencies\n");
+ printf("\t--autoremove Remove packages that were installed\n");
+ printf("\t automatically to satisfy dependencies\n");
+ printf("\t-t Specify tmp-dir.\n");
+ printf("\t--tmp-dir Specify tmp-dir.\n");
+
+ printf("\n");
+
+ printf(" regexp could be something like 'pkgname*' '*file*' or similar\n");
+ printf(" e.g. opkg info 'libstd*' or opkg search '*libop*' or opkg remove 'libncur*'\n");
+
+ /* --force-removal-of-essential-packages Let opkg remove essential packages.
+ Using this option is almost guaranteed to break your system, hence this option
+ is not even advertised in the usage statement. */
+
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opts, err = -1;
+ char *cmd_name;
+ opkg_cmd_t *cmd;
+ int nocheckfordirorfile = 0;
+ int noreadfeedsfile = 0;
+
+ if (opkg_conf_init())
+ goto err0;
+
+ conf->verbosity = NOTICE;
+
+ opts = args_parse(argc, argv);
+ if (opts == argc || opts < 0) {
+ fprintf(stderr, "opkg must have one sub-command argument\n");
+ usage();
+ }
+
+ cmd_name = argv[opts++];
+
+ if (!strcmp(cmd_name,"print-architecture") ||
+ !strcmp(cmd_name,"print_architecture") ||
+ !strcmp(cmd_name,"print-installation-architecture") ||
+ !strcmp(cmd_name,"print_installation_architecture") )
+ nocheckfordirorfile = 1;
+
+ if (!strcmp(cmd_name,"flag") ||
+ !strcmp(cmd_name,"configure") ||
+ !strcmp(cmd_name,"remove") ||
+ !strcmp(cmd_name,"files") ||
+ !strcmp(cmd_name,"search") ||
+ !strcmp(cmd_name,"compare_versions") ||
+ !strcmp(cmd_name,"compare-versions") ||
+ !strcmp(cmd_name,"list_installed") ||
+ !strcmp(cmd_name,"list-installed") ||
+ !strcmp(cmd_name,"list_changed_conffiles") ||
+ !strcmp(cmd_name,"list-changed-conffiles") ||
+ !strcmp(cmd_name,"status") )
+ noreadfeedsfile = 1;
+
+ cmd = opkg_cmd_find(cmd_name);
+ if (cmd == NULL) {
+ fprintf(stderr, "%s: unknown sub-command %s\n", argv[0],
+ cmd_name);
+ usage();
+ }
+
+ conf->pfm = cmd->pfm;
+
+ if (opkg_conf_load())
+ goto err0;
+
+ if (!nocheckfordirorfile) {
+ if (!noreadfeedsfile) {
+ if (pkg_hash_load_feeds())
+ goto err1;
+ }
+
+ if (pkg_hash_load_status_files())
+ goto err1;
+ }
+
+ if (cmd->requires_args && opts == argc) {
+ fprintf(stderr,
+ "%s: the ``%s'' command requires at least one argument\n",
+ argv[0], cmd_name);
+ usage();
+ }
+
+ err = opkg_cmd_exec(cmd, argc - opts, (const char **) (argv + opts));
+
+#ifdef HAVE_CURL
+ opkg_curl_cleanup();
+#endif
+err1:
+ opkg_conf_deinit();
+
+err0:
+ print_error_list();
+ free_error_list();
+
+ return err;
+}
diff --git a/src/tests/.svn/all-wcprops b/src/tests/.svn/all-wcprops
new file mode 100644
index 0000000..cf285ed
--- /dev/null
+++ b/src/tests/.svn/all-wcprops
@@ -0,0 +1,35 @@
+K 25
+svn:wc:ra_dav:version-url
+V 29
+/svn/!svn/ver/634/trunk/tests
+END
+opkg_hash_test.c
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svn/!svn/ver/552/trunk/tests/opkg_hash_test.c
+END
+opkg_active_list_test.c
+K 25
+svn:wc:ra_dav:version-url
+V 53
+/svn/!svn/ver/552/trunk/tests/opkg_active_list_test.c
+END
+libopkg_test.c
+K 25
+svn:wc:ra_dav:version-url
+V 44
+/svn/!svn/ver/622/trunk/tests/libopkg_test.c
+END
+Makefile.am
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/474/trunk/tests/Makefile.am
+END
+opkg_extract_test.c
+K 25
+svn:wc:ra_dav:version-url
+V 49
+/svn/!svn/ver/552/trunk/tests/opkg_extract_test.c
+END
diff --git a/src/tests/.svn/entries b/src/tests/.svn/entries
new file mode 100644
index 0000000..930a7e8
--- /dev/null
+++ b/src/tests/.svn/entries
@@ -0,0 +1,201 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/tests
+http://opkg.googlecode.com/svn
+
+
+
+2012-01-19T13:51:59.790020Z
+634
+pixdamix@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
+opkg_hash_test.c
+file
+
+
+
+
+2012-02-03T08:11:57.359042Z
+42ded85fe3c9d5d5427ee6f07b629828
+2010-08-18T03:39:02.973664Z
+552
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2134
+
+opkg_active_list_test.c
+file
+
+
+
+
+2012-02-03T08:11:57.359042Z
+3a5506764a10f969300fefc107066e3b
+2010-08-18T03:39:02.973664Z
+552
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4626
+
+libopkg_test.c
+file
+
+
+
+
+2012-02-03T08:11:57.359042Z
+e37fec6637c1992e52ec2d4bad07776d
+2011-05-26T00:51:50.330823Z
+622
+graham.gower@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6385
+
+Makefile.am
+file
+
+
+
+
+2012-02-03T08:11:57.359042Z
+4f0297e9e0f54993a1809827d77b12ae
+2009-12-09T06:05:08.329580Z
+474
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+907
+
+regress
+dir
+
+opkg_extract_test.c
+file
+
+
+
+
+2012-02-03T08:11:57.359042Z
+ab5ec2fffab9a3b9ab566b56c9ee8d11
+2010-08-18T03:39:02.973664Z
+552
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1152
+
diff --git a/src/tests/.svn/text-base/Makefile.am.svn-base b/src/tests/.svn/text-base/Makefile.am.svn-base
new file mode 100644
index 0000000..1a6f565
--- /dev/null
+++ b/src/tests/.svn/text-base/Makefile.am.svn-base
@@ -0,0 +1,23 @@
+AM_CFLAGS = $(ALL_CFLAGS) -Wall -g -O3 -I${top_srcdir}/libopkg
+
+#noinst_PROGRAMS = opkg_hash_test opkg_extract_test
+#noinst_PROGRAMS = libopkg_test opkg_active_list_test
+noinst_PROGRAMS = libopkg_test
+
+#opkg_hash_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la
+#opkg_hash_test_SOURCES = opkg_hash_test.c
+#opkg_hash_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+
+#opkg_extract_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la
+#opkg_extract_test_SOURCES = opkg_extract_test.c
+#opkg_extract_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+
+#opkg_active_list_test_LDADD = $(top_builddir)/libopkg/active_list.o
+#opkg_active_list_test_SOURCES = opkg_active_list_test.c
+#opkg_active_list_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+
+libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.la
+libopkg_test_SOURCE = libopkg_test.c
+libopkg_test_LDFLAGS = -static
+
+
diff --git a/src/tests/.svn/text-base/libopkg_test.c.svn-base b/src/tests/.svn/text-base/libopkg_test.c.svn-base
new file mode 100644
index 0000000..21f100e
--- /dev/null
+++ b/src/tests/.svn/text-base/libopkg_test.c.svn-base
@@ -0,0 +1,261 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <opkg.h>
+
+int opkg_state_changed;
+pkg_t *find_pkg = NULL;
+
+
+#define TEST_PACKAGE "aspell"
+
+void
+progress_callback (const opkg_progress_data_t *progress, void *data)
+{
+ printf ("\r%s %3d%%\n", (char*) data, progress->percentage);
+ fflush (stdout);
+}
+
+static void list_pkg(pkg_t *pkg)
+{
+ char *v = pkg_version_str_alloc(pkg);
+ printf ("%s - %s\n", pkg->name, v);
+ free(v);
+}
+
+void
+package_list_installed_callback (pkg_t *pkg, void *data)
+{
+ if (pkg->state_status == SS_INSTALLED)
+ list_pkg(pkg);
+}
+
+void
+package_list_callback (pkg_t *pkg, void *data)
+{
+ static int install_count = 0;
+ static int total_count = 0;
+
+ if (pkg->state_status == SS_INSTALLED)
+ install_count++;
+
+ total_count++;
+
+ printf ("\rPackage count: %d Installed, %d Total Available", install_count, total_count);
+ fflush (stdout);
+
+ if (!find_pkg)
+ {
+ /* store the first package to print out later */
+ find_pkg = pkg;
+ }
+}
+
+void
+package_list_upgradable_callback (pkg_t *pkg, void *data)
+{
+ list_pkg(pkg);
+}
+
+void
+print_package (pkg_t *pkg)
+{
+ char *v = pkg_version_str_alloc(pkg);
+ printf (
+ "Name: %s\n"
+ "Version: %s\n"
+ "Repository: %s\n"
+ "Architecture: %s\n"
+ "Description: %s\n"
+ "Tags: %s\n"
+ "Size: %ld\n"
+ "Status: %d\n",
+ pkg->name,
+ v,
+ pkg->src->name,
+ pkg->architecture,
+ pkg->description,
+ pkg->tags? pkg->tags : "",
+ pkg->size,
+ pkg->state_status);
+ free(v);
+}
+
+
+void
+opkg_test (void)
+{
+ int err;
+ pkg_t *pkg;
+
+ err = opkg_update_package_lists (progress_callback, "Updating...");
+ printf ("\nopkg_update_package_lists returned %d\n", err);
+
+ opkg_list_packages (package_list_callback, NULL);
+ printf ("\n");
+
+ if (find_pkg)
+ {
+ printf ("Finding package \"%s\"\n", find_pkg->name);
+ pkg = opkg_find_package (find_pkg->name, find_pkg->version, find_pkg->architecture, find_pkg->src->name);
+ if (pkg)
+ {
+ print_package (pkg);
+ }
+ else
+ printf ("Package \"%s\" not found!\n", find_pkg->name);
+ }
+ else
+ printf ("No package available to test find_package.\n");
+
+ err = opkg_install_package (TEST_PACKAGE, progress_callback, "Installing...");
+ printf ("\nopkg_install_package returned %d\n", err);
+
+ err = opkg_upgrade_package (TEST_PACKAGE, progress_callback, "Upgrading...");
+ printf ("\nopkg_upgrade_package returned %d\n", err);
+
+ err = opkg_remove_package (TEST_PACKAGE, progress_callback, "Removing...");
+ printf ("\nopkg_remove_package returned %d\n", err);
+
+ printf ("Listing upgradable packages...\n");
+ opkg_list_upgradable_packages (package_list_upgradable_callback, NULL);
+
+ err = opkg_upgrade_all (progress_callback, "Upgrading all...");
+ printf ("\nopkg_upgrade_all returned %d\n", err);
+
+}
+
+int
+main (int argc, char **argv)
+{
+ pkg_t *pkg;
+ int err;
+
+ if (argc < 2)
+ {
+ printf ("Usage: %s command\n"
+ "\nCommands:\n"
+ "\tupdate - Update package lists\n"
+ "\tfind [package] - Print details of the specified package\n"
+ "\tinstall [package] - Install the specified package\n"
+ "\tupgrade [package] - Upgrade the specified package\n"
+ "\tlist upgrades - List the available upgrades\n"
+ "\tlist all - List all available packages\n"
+ "\tlist installed - List all the installed packages\n"
+ "\tremove [package] - Remove the specified package\n"
+ "\trping - Reposiroties ping, check the accessibility of repositories\n"
+ "\ttest - Run test script\n"
+ , basename (argv[0]));
+ exit (0);
+ }
+
+ setenv("OFFLINE_ROOT", "/tmp", 0);
+
+ if (opkg_new ()) {
+ printf("opkg_new() failed. This sucks.\n");
+ print_error_list();
+ return 1;
+ }
+
+ char *cache;
+ opkg_set_option("cache", "|asdf|");
+ if (opkg_get_option("cache", &cache) != -1) {
+ printf("cache=``%s''\n", cache);
+ }
+
+ int verb;
+ opkg_set_option("verbosity", (void *)3);
+ if (opkg_get_option("verbosity", &verb) != -1) {
+ printf("verbosity=%d\n", verb);
+ }
+
+ switch (argv[1][0])
+ {
+ case 'f':
+ pkg = opkg_find_package (argv[2], NULL, NULL, NULL);
+ if (pkg)
+ {
+ print_package (pkg);
+ }
+ else
+ printf ("Package \"%s\" not found!\n", find_pkg->name);
+ break;
+ case 'i':
+ err = opkg_install_package (argv[2], progress_callback, "Installing...");
+ printf ("\nopkg_install_package returned %d\n", err);
+ break;
+
+ case 'u':
+ if (argv[1][2] == 'd')
+ {
+ err = opkg_update_package_lists (progress_callback, "Updating...");
+ printf ("\nopkg_update_package_lists returned %d\n", err);
+ break;
+ }
+ else
+ {
+ if (argc < 3)
+ {
+ err = opkg_upgrade_all (progress_callback, "Upgrading all...");
+ printf ("\nopkg_upgrade_all returned %d\n", err);
+ }
+ else
+ {
+ err = opkg_upgrade_package (argv[2], progress_callback, "Upgrading...");
+ printf ("\nopkg_upgrade_package returned %d\n", err);
+ }
+ }
+ break;
+
+ case 'l':
+ if (argc < 3)
+ {
+ printf ("Please specify one either all, installed or upgrades\n");
+ }
+ else
+ {
+ switch (argv[2][0])
+ {
+ case 'u':
+ printf ("Listing upgradable packages...\n");
+ opkg_list_upgradable_packages (package_list_upgradable_callback, NULL);
+ break;
+ case 'a':
+ printf ("Listing all packages...\n");
+ opkg_list_packages (package_list_callback, NULL);
+ printf ("\n");
+ break;
+ case 'i':
+ printf ("Listing installed packages...\n");
+ opkg_list_packages (package_list_installed_callback, NULL);
+ break;
+ default:
+ printf ("Unknown list option \"%s\"\n", argv[2]);
+ }
+ }
+ break;
+
+ case 'r':
+ if (argv[1][1] == 'e')
+ {
+ err = opkg_remove_package (argv[2], progress_callback, "Removing...");
+ printf ("\nopkg_remove_package returned %d\n", err);
+ break;
+ }else if (argv[1][1] == 'p')
+ {
+ err = opkg_repository_accessibility_check();
+ printf("\nopkg_repository_accessibility_check returned (%d)\n", err);
+ break;
+ }
+
+ default:
+ printf ("Unknown command \"%s\"\n", argv[1]);
+ }
+
+
+ opkg_free ();
+
+ return 0;
+}
diff --git a/src/tests/.svn/text-base/opkg_active_list_test.c.svn-base b/src/tests/.svn/text-base/opkg_active_list_test.c.svn-base
new file mode 100644
index 0000000..b6af3b3
--- /dev/null
+++ b/src/tests/.svn/text-base/opkg_active_list_test.c.svn-base
@@ -0,0 +1,145 @@
+/* opkg_active_list.c - the opkg package management system
+
+ Tick Chen <tick@openmoko.com>
+
+ Copyright (C) 2008 Openmoko
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT 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 <stdlib.h>
+#include <libopkg/active_list.h>
+#include <active_list.h>
+#include <stdio.h>
+
+struct active_test {
+ char *str;
+ struct active_list list;
+};
+
+struct active_test *active_test_new(char *str) {
+ struct active_test *ans = (struct active_test *)calloc(1, sizeof(struct active_test));
+ ans->str = str;
+ active_list_init(&ans->list);
+ return ans;
+}
+void active_test_add(struct active_list *head, struct active_test *node) {
+ active_list_add(head, &node->list);
+}
+
+void active_test_add_depend(struct active_test *A, struct active_test *B) {
+ active_list_add_depend(&A->list, &B->list);
+}
+
+/*
+.--A---B----C----D-----E----F
+ | |__k---L
+ | |_ N
+ |__ G ---H ---I---J
+ |_M |_O
+
+Then the sequence will be
++: G M H I O J A B K N L C D E F
+-: F E D C L N K B A J O I H M G
+*/
+void make_list(struct active_list *head) {
+ struct active_test *A = active_test_new("A");
+ struct active_test *B = active_test_new("B");
+ struct active_test *C = active_test_new("C");
+ struct active_test *D = active_test_new("D");
+ struct active_test *E = active_test_new("E");
+ struct active_test *F = active_test_new("F");
+ struct active_test *G = active_test_new("G");
+ struct active_test *H = active_test_new("H");
+ struct active_test *I = active_test_new("I");
+ struct active_test *J = active_test_new("J");
+ struct active_test *K = active_test_new("K");
+ struct active_test *L = active_test_new("L");
+ struct active_test *M = active_test_new("M");
+ struct active_test *N = active_test_new("N");
+ struct active_test *O = active_test_new("O");
+
+ active_test_add(head, A);
+ active_test_add(head, B);
+ active_test_add(head, C);
+ active_test_add(head, D);
+ active_test_add(head, E);
+ active_test_add(head, F);
+ active_test_add(head, G);
+ active_test_add(head, H);
+ active_test_add(head, I);
+ active_test_add(head, J);
+ active_test_add(head, K);
+ active_test_add(head, L);
+ active_test_add(head, M);
+ active_test_add(head, N);
+ active_test_add(head, O);
+ active_test_add_depend(H, M);
+ active_test_add_depend(A, G);
+ active_test_add_depend(A, H);
+ active_test_add_depend(A, I);
+ active_test_add_depend(A, J);
+ active_test_add_depend(J, O);
+ active_test_add_depend(C, K);
+ active_test_add_depend(C, L);
+ active_test_add_depend(L, N);
+}
+
+int active_test_compare(const void *a, const void *b) {
+ struct active_list *first = (struct active_list *)a;
+ struct active_list *second = (struct active_list *)b;
+ return strcmp(list_entry(first, struct active_test, list),
+ list_entry(second, struct active_test, list));
+}
+
+void show_list(struct active_list *head) {
+ struct active_list *ptr;
+ struct active_test *test;
+ for(ptr = active_list_next(head, NULL); ptr ;ptr = active_list_next(head, ptr)) {
+ test = list_entry(ptr, struct active_test, list);
+ printf ("%s ",test->str);
+ }
+ printf("\n");
+}
+
+int main (void) {
+ struct active_list head;
+ struct active_list *ptr;
+ struct active_test *test;
+ active_list_init(&head);
+ make_list(&head);
+
+ printf("pos order: ");
+ show_list(&head);
+/* for(ptr = active_list_next(&head, &head); ptr ;ptr = active_list_next(&head, ptr)) {
+ test = list_entry(ptr, struct active_test, list);
+ printf ("%s ",test->str);
+ }*/
+ printf("neg order: ");
+ for(ptr = active_list_prev(&head, &head); ptr ;ptr = active_list_prev(&head, ptr)) {
+ test = list_entry(ptr, struct active_test, list);
+ printf ("%s ",test->str);
+ }
+ printf("\npos order after sort: ");
+ active_list_sort(&head, &active_test_compare);
+ show_list(&head);
+
+ printf("after clear: ");
+ active_list_clear(&head);
+ for(ptr = active_list_next(&head, NULL); ptr ;ptr = active_list_next(&head, ptr)) {
+ test = list_entry(ptr, struct active_test, list);
+ printf ("%s ",test->str);
+ }
+ printf("\n");
+
+
+}
diff --git a/src/tests/.svn/text-base/opkg_extract_test.c.svn-base b/src/tests/.svn/text-base/opkg_extract_test.c.svn-base
new file mode 100644
index 0000000..9754691
--- /dev/null
+++ b/src/tests/.svn/text-base/opkg_extract_test.c.svn-base
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <libbb/libbb.h>
+
+/*
+ * build thus:
+
+ * gcc -o opkg_extract_test opkg_extract_test.c -I./busybox-0.60.2/libbb -L./busybox-0.60.2 -lbb
+ *
+ */
+const char * applet_name;
+
+int main(int argc, char * argv[])
+{
+ /*
+ * see libbb.h and let your imagination run wild
+ * or, set the last item below to extract_one_to_buffer, and you get the control file in
+ * "returned"
+ * or, set the last one to extract_all_to_fs, and, well, guess what happens
+ */
+
+ /* enum extract_functions_e dowhat = extract_control_tar_gz | extract_unconditional | extract_one_to_buffer; */
+ enum extract_functions_e dowhat = extract_control_tar_gz | extract_all_to_fs | extract_preserve_date;
+ char * returned;
+ char * filename;
+
+ if(argc < 2){
+ fprintf(stderr, "syntax: %s <opkg file> [<file_to_extract>]\n", argv[0]);
+ exit(0);
+ }
+
+ if (argc < 3){
+ filename=NULL;
+ } else {
+ filename = argv[2];
+ }
+
+ returned = deb_extract(argv[1], stdout, dowhat, NULL, filename);
+
+ if(returned)
+ fprintf(stderr, "returned %s\n", returned);
+ else
+ fprintf(stderr, "extract returned nuthin'\n");
+
+ return 0;
+}
diff --git a/src/tests/.svn/text-base/opkg_hash_test.c.svn-base b/src/tests/.svn/text-base/opkg_hash_test.c.svn-base
new file mode 100644
index 0000000..de1d82c
--- /dev/null
+++ b/src/tests/.svn/text-base/opkg_hash_test.c.svn-base
@@ -0,0 +1,79 @@
+/* opkg_hash_test.c - the itsy 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 <libopkg/opkg.h>
+
+#include <libopkg/hash_table.h>
+#include <libopkg/opkg_utils.h>
+#include <libopkg/pkg_hash.h>
+
+int main(int argc, char *argv[])
+{
+ opkg_conf_t conf;
+ hash_table_t *hash = &conf.pkg_hash;
+ pkg_vec_t * pkg_vec;
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s <pkgs_file1> <pkgs_file2> [pkg_name...]\n", argv[0]);
+ exit(1);
+ }
+ pkg_hash_init("test", hash, 1024);
+
+ pkg_hash_add_from_file(&conf, argv[1], NULL, NULL, 0);
+ pkg_hash_add_from_file(&conf, argv[2], NULL, NULL, 0);
+
+ if (argc < 4) {
+ pkg_print_info( pkg_hash_fetch_by_name_version(hash, "libc6", "2.2.3-2"), stdout);
+ /* for(i = 0; i < pkg_vec->len; i++)
+ pkg_print(pkg_vec->pkgs[i], stdout);
+ */
+ } else {
+ int i, j, k;
+ char **unresolved;
+
+ pkg_vec_t * dep_vec;
+ for (i = 3; i < argc; i++) {
+ pkg_vec = pkg_vec_fetch_by_name(hash, argv[i]);
+ if (pkg_vec == NULL) {
+ fprintf(stderr, "*** WARNING: Unknown package: %s\n\n", argv[i]);
+ continue;
+ }
+
+ for(j = 0; j < pkg_vec->len; j++){
+ pkg_print_info(pkg_vec->pkgs[j], stdout);
+ dep_vec = pkg_vec_alloc();
+ pkg_hash_fetch_unsatisfied_dependencies(&conf,
+ pkg_vec->pkgs[j],
+ dep_vec,
+ &unresolved);
+ if(dep_vec){
+ fprintf(stderr, "and the unsatisfied dependencies are:\n");
+ for(k = 0; k < dep_vec->len; k++){
+ fprintf(stderr, "%s version %s\n", dep_vec->pkgs[k]->name, dep_vec->pkgs[k]->version);
+ }
+ }
+
+ fputs("", stdout);
+
+ }
+ }
+ }
+
+ pkg_hash_deinit(hash);
+
+ return 0;
+}
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
new file mode 100644
index 0000000..1a6f565
--- /dev/null
+++ b/src/tests/Makefile.am
@@ -0,0 +1,23 @@
+AM_CFLAGS = $(ALL_CFLAGS) -Wall -g -O3 -I${top_srcdir}/libopkg
+
+#noinst_PROGRAMS = opkg_hash_test opkg_extract_test
+#noinst_PROGRAMS = libopkg_test opkg_active_list_test
+noinst_PROGRAMS = libopkg_test
+
+#opkg_hash_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la
+#opkg_hash_test_SOURCES = opkg_hash_test.c
+#opkg_hash_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+
+#opkg_extract_test_LDADD = $(top_builddir)/libbb/libbb.la $(top_builddir)/libopkg/libopkg.la
+#opkg_extract_test_SOURCES = opkg_extract_test.c
+#opkg_extract_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+
+#opkg_active_list_test_LDADD = $(top_builddir)/libopkg/active_list.o
+#opkg_active_list_test_SOURCES = opkg_active_list_test.c
+#opkg_active_list_test_CFLAGS = $(ALL_CFLAGS) -I$(top_srcdir)
+
+libopkg_test_LDADD = $(top_builddir)/libopkg/libopkg.la
+libopkg_test_SOURCE = libopkg_test.c
+libopkg_test_LDFLAGS = -static
+
+
diff --git a/src/tests/libopkg_test.c b/src/tests/libopkg_test.c
new file mode 100644
index 0000000..21f100e
--- /dev/null
+++ b/src/tests/libopkg_test.c
@@ -0,0 +1,261 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <opkg.h>
+
+int opkg_state_changed;
+pkg_t *find_pkg = NULL;
+
+
+#define TEST_PACKAGE "aspell"
+
+void
+progress_callback (const opkg_progress_data_t *progress, void *data)
+{
+ printf ("\r%s %3d%%\n", (char*) data, progress->percentage);
+ fflush (stdout);
+}
+
+static void list_pkg(pkg_t *pkg)
+{
+ char *v = pkg_version_str_alloc(pkg);
+ printf ("%s - %s\n", pkg->name, v);
+ free(v);
+}
+
+void
+package_list_installed_callback (pkg_t *pkg, void *data)
+{
+ if (pkg->state_status == SS_INSTALLED)
+ list_pkg(pkg);
+}
+
+void
+package_list_callback (pkg_t *pkg, void *data)
+{
+ static int install_count = 0;
+ static int total_count = 0;
+
+ if (pkg->state_status == SS_INSTALLED)
+ install_count++;
+
+ total_count++;
+
+ printf ("\rPackage count: %d Installed, %d Total Available", install_count, total_count);
+ fflush (stdout);
+
+ if (!find_pkg)
+ {
+ /* store the first package to print out later */
+ find_pkg = pkg;
+ }
+}
+
+void
+package_list_upgradable_callback (pkg_t *pkg, void *data)
+{
+ list_pkg(pkg);
+}
+
+void
+print_package (pkg_t *pkg)
+{
+ char *v = pkg_version_str_alloc(pkg);
+ printf (
+ "Name: %s\n"
+ "Version: %s\n"
+ "Repository: %s\n"
+ "Architecture: %s\n"
+ "Description: %s\n"
+ "Tags: %s\n"
+ "Size: %ld\n"
+ "Status: %d\n",
+ pkg->name,
+ v,
+ pkg->src->name,
+ pkg->architecture,
+ pkg->description,
+ pkg->tags? pkg->tags : "",
+ pkg->size,
+ pkg->state_status);
+ free(v);
+}
+
+
+void
+opkg_test (void)
+{
+ int err;
+ pkg_t *pkg;
+
+ err = opkg_update_package_lists (progress_callback, "Updating...");
+ printf ("\nopkg_update_package_lists returned %d\n", err);
+
+ opkg_list_packages (package_list_callback, NULL);
+ printf ("\n");
+
+ if (find_pkg)
+ {
+ printf ("Finding package \"%s\"\n", find_pkg->name);
+ pkg = opkg_find_package (find_pkg->name, find_pkg->version, find_pkg->architecture, find_pkg->src->name);
+ if (pkg)
+ {
+ print_package (pkg);
+ }
+ else
+ printf ("Package \"%s\" not found!\n", find_pkg->name);
+ }
+ else
+ printf ("No package available to test find_package.\n");
+
+ err = opkg_install_package (TEST_PACKAGE, progress_callback, "Installing...");
+ printf ("\nopkg_install_package returned %d\n", err);
+
+ err = opkg_upgrade_package (TEST_PACKAGE, progress_callback, "Upgrading...");
+ printf ("\nopkg_upgrade_package returned %d\n", err);
+
+ err = opkg_remove_package (TEST_PACKAGE, progress_callback, "Removing...");
+ printf ("\nopkg_remove_package returned %d\n", err);
+
+ printf ("Listing upgradable packages...\n");
+ opkg_list_upgradable_packages (package_list_upgradable_callback, NULL);
+
+ err = opkg_upgrade_all (progress_callback, "Upgrading all...");
+ printf ("\nopkg_upgrade_all returned %d\n", err);
+
+}
+
+int
+main (int argc, char **argv)
+{
+ pkg_t *pkg;
+ int err;
+
+ if (argc < 2)
+ {
+ printf ("Usage: %s command\n"
+ "\nCommands:\n"
+ "\tupdate - Update package lists\n"
+ "\tfind [package] - Print details of the specified package\n"
+ "\tinstall [package] - Install the specified package\n"
+ "\tupgrade [package] - Upgrade the specified package\n"
+ "\tlist upgrades - List the available upgrades\n"
+ "\tlist all - List all available packages\n"
+ "\tlist installed - List all the installed packages\n"
+ "\tremove [package] - Remove the specified package\n"
+ "\trping - Reposiroties ping, check the accessibility of repositories\n"
+ "\ttest - Run test script\n"
+ , basename (argv[0]));
+ exit (0);
+ }
+
+ setenv("OFFLINE_ROOT", "/tmp", 0);
+
+ if (opkg_new ()) {
+ printf("opkg_new() failed. This sucks.\n");
+ print_error_list();
+ return 1;
+ }
+
+ char *cache;
+ opkg_set_option("cache", "|asdf|");
+ if (opkg_get_option("cache", &cache) != -1) {
+ printf("cache=``%s''\n", cache);
+ }
+
+ int verb;
+ opkg_set_option("verbosity", (void *)3);
+ if (opkg_get_option("verbosity", &verb) != -1) {
+ printf("verbosity=%d\n", verb);
+ }
+
+ switch (argv[1][0])
+ {
+ case 'f':
+ pkg = opkg_find_package (argv[2], NULL, NULL, NULL);
+ if (pkg)
+ {
+ print_package (pkg);
+ }
+ else
+ printf ("Package \"%s\" not found!\n", find_pkg->name);
+ break;
+ case 'i':
+ err = opkg_install_package (argv[2], progress_callback, "Installing...");
+ printf ("\nopkg_install_package returned %d\n", err);
+ break;
+
+ case 'u':
+ if (argv[1][2] == 'd')
+ {
+ err = opkg_update_package_lists (progress_callback, "Updating...");
+ printf ("\nopkg_update_package_lists returned %d\n", err);
+ break;
+ }
+ else
+ {
+ if (argc < 3)
+ {
+ err = opkg_upgrade_all (progress_callback, "Upgrading all...");
+ printf ("\nopkg_upgrade_all returned %d\n", err);
+ }
+ else
+ {
+ err = opkg_upgrade_package (argv[2], progress_callback, "Upgrading...");
+ printf ("\nopkg_upgrade_package returned %d\n", err);
+ }
+ }
+ break;
+
+ case 'l':
+ if (argc < 3)
+ {
+ printf ("Please specify one either all, installed or upgrades\n");
+ }
+ else
+ {
+ switch (argv[2][0])
+ {
+ case 'u':
+ printf ("Listing upgradable packages...\n");
+ opkg_list_upgradable_packages (package_list_upgradable_callback, NULL);
+ break;
+ case 'a':
+ printf ("Listing all packages...\n");
+ opkg_list_packages (package_list_callback, NULL);
+ printf ("\n");
+ break;
+ case 'i':
+ printf ("Listing installed packages...\n");
+ opkg_list_packages (package_list_installed_callback, NULL);
+ break;
+ default:
+ printf ("Unknown list option \"%s\"\n", argv[2]);
+ }
+ }
+ break;
+
+ case 'r':
+ if (argv[1][1] == 'e')
+ {
+ err = opkg_remove_package (argv[2], progress_callback, "Removing...");
+ printf ("\nopkg_remove_package returned %d\n", err);
+ break;
+ }else if (argv[1][1] == 'p')
+ {
+ err = opkg_repository_accessibility_check();
+ printf("\nopkg_repository_accessibility_check returned (%d)\n", err);
+ break;
+ }
+
+ default:
+ printf ("Unknown command \"%s\"\n", argv[1]);
+ }
+
+
+ opkg_free ();
+
+ return 0;
+}
diff --git a/src/tests/opkg_active_list_test.c b/src/tests/opkg_active_list_test.c
new file mode 100644
index 0000000..b6af3b3
--- /dev/null
+++ b/src/tests/opkg_active_list_test.c
@@ -0,0 +1,145 @@
+/* opkg_active_list.c - the opkg package management system
+
+ Tick Chen <tick@openmoko.com>
+
+ Copyright (C) 2008 Openmoko
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT 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 <stdlib.h>
+#include <libopkg/active_list.h>
+#include <active_list.h>
+#include <stdio.h>
+
+struct active_test {
+ char *str;
+ struct active_list list;
+};
+
+struct active_test *active_test_new(char *str) {
+ struct active_test *ans = (struct active_test *)calloc(1, sizeof(struct active_test));
+ ans->str = str;
+ active_list_init(&ans->list);
+ return ans;
+}
+void active_test_add(struct active_list *head, struct active_test *node) {
+ active_list_add(head, &node->list);
+}
+
+void active_test_add_depend(struct active_test *A, struct active_test *B) {
+ active_list_add_depend(&A->list, &B->list);
+}
+
+/*
+.--A---B----C----D-----E----F
+ | |__k---L
+ | |_ N
+ |__ G ---H ---I---J
+ |_M |_O
+
+Then the sequence will be
++: G M H I O J A B K N L C D E F
+-: F E D C L N K B A J O I H M G
+*/
+void make_list(struct active_list *head) {
+ struct active_test *A = active_test_new("A");
+ struct active_test *B = active_test_new("B");
+ struct active_test *C = active_test_new("C");
+ struct active_test *D = active_test_new("D");
+ struct active_test *E = active_test_new("E");
+ struct active_test *F = active_test_new("F");
+ struct active_test *G = active_test_new("G");
+ struct active_test *H = active_test_new("H");
+ struct active_test *I = active_test_new("I");
+ struct active_test *J = active_test_new("J");
+ struct active_test *K = active_test_new("K");
+ struct active_test *L = active_test_new("L");
+ struct active_test *M = active_test_new("M");
+ struct active_test *N = active_test_new("N");
+ struct active_test *O = active_test_new("O");
+
+ active_test_add(head, A);
+ active_test_add(head, B);
+ active_test_add(head, C);
+ active_test_add(head, D);
+ active_test_add(head, E);
+ active_test_add(head, F);
+ active_test_add(head, G);
+ active_test_add(head, H);
+ active_test_add(head, I);
+ active_test_add(head, J);
+ active_test_add(head, K);
+ active_test_add(head, L);
+ active_test_add(head, M);
+ active_test_add(head, N);
+ active_test_add(head, O);
+ active_test_add_depend(H, M);
+ active_test_add_depend(A, G);
+ active_test_add_depend(A, H);
+ active_test_add_depend(A, I);
+ active_test_add_depend(A, J);
+ active_test_add_depend(J, O);
+ active_test_add_depend(C, K);
+ active_test_add_depend(C, L);
+ active_test_add_depend(L, N);
+}
+
+int active_test_compare(const void *a, const void *b) {
+ struct active_list *first = (struct active_list *)a;
+ struct active_list *second = (struct active_list *)b;
+ return strcmp(list_entry(first, struct active_test, list),
+ list_entry(second, struct active_test, list));
+}
+
+void show_list(struct active_list *head) {
+ struct active_list *ptr;
+ struct active_test *test;
+ for(ptr = active_list_next(head, NULL); ptr ;ptr = active_list_next(head, ptr)) {
+ test = list_entry(ptr, struct active_test, list);
+ printf ("%s ",test->str);
+ }
+ printf("\n");
+}
+
+int main (void) {
+ struct active_list head;
+ struct active_list *ptr;
+ struct active_test *test;
+ active_list_init(&head);
+ make_list(&head);
+
+ printf("pos order: ");
+ show_list(&head);
+/* for(ptr = active_list_next(&head, &head); ptr ;ptr = active_list_next(&head, ptr)) {
+ test = list_entry(ptr, struct active_test, list);
+ printf ("%s ",test->str);
+ }*/
+ printf("neg order: ");
+ for(ptr = active_list_prev(&head, &head); ptr ;ptr = active_list_prev(&head, ptr)) {
+ test = list_entry(ptr, struct active_test, list);
+ printf ("%s ",test->str);
+ }
+ printf("\npos order after sort: ");
+ active_list_sort(&head, &active_test_compare);
+ show_list(&head);
+
+ printf("after clear: ");
+ active_list_clear(&head);
+ for(ptr = active_list_next(&head, NULL); ptr ;ptr = active_list_next(&head, ptr)) {
+ test = list_entry(ptr, struct active_test, list);
+ printf ("%s ",test->str);
+ }
+ printf("\n");
+
+
+}
diff --git a/src/tests/opkg_extract_test.c b/src/tests/opkg_extract_test.c
new file mode 100644
index 0000000..9754691
--- /dev/null
+++ b/src/tests/opkg_extract_test.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <libbb/libbb.h>
+
+/*
+ * build thus:
+
+ * gcc -o opkg_extract_test opkg_extract_test.c -I./busybox-0.60.2/libbb -L./busybox-0.60.2 -lbb
+ *
+ */
+const char * applet_name;
+
+int main(int argc, char * argv[])
+{
+ /*
+ * see libbb.h and let your imagination run wild
+ * or, set the last item below to extract_one_to_buffer, and you get the control file in
+ * "returned"
+ * or, set the last one to extract_all_to_fs, and, well, guess what happens
+ */
+
+ /* enum extract_functions_e dowhat = extract_control_tar_gz | extract_unconditional | extract_one_to_buffer; */
+ enum extract_functions_e dowhat = extract_control_tar_gz | extract_all_to_fs | extract_preserve_date;
+ char * returned;
+ char * filename;
+
+ if(argc < 2){
+ fprintf(stderr, "syntax: %s <opkg file> [<file_to_extract>]\n", argv[0]);
+ exit(0);
+ }
+
+ if (argc < 3){
+ filename=NULL;
+ } else {
+ filename = argv[2];
+ }
+
+ returned = deb_extract(argv[1], stdout, dowhat, NULL, filename);
+
+ if(returned)
+ fprintf(stderr, "returned %s\n", returned);
+ else
+ fprintf(stderr, "extract returned nuthin'\n");
+
+ return 0;
+}
diff --git a/src/tests/opkg_hash_test.c b/src/tests/opkg_hash_test.c
new file mode 100644
index 0000000..de1d82c
--- /dev/null
+++ b/src/tests/opkg_hash_test.c
@@ -0,0 +1,79 @@
+/* opkg_hash_test.c - the itsy 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 <libopkg/opkg.h>
+
+#include <libopkg/hash_table.h>
+#include <libopkg/opkg_utils.h>
+#include <libopkg/pkg_hash.h>
+
+int main(int argc, char *argv[])
+{
+ opkg_conf_t conf;
+ hash_table_t *hash = &conf.pkg_hash;
+ pkg_vec_t * pkg_vec;
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s <pkgs_file1> <pkgs_file2> [pkg_name...]\n", argv[0]);
+ exit(1);
+ }
+ pkg_hash_init("test", hash, 1024);
+
+ pkg_hash_add_from_file(&conf, argv[1], NULL, NULL, 0);
+ pkg_hash_add_from_file(&conf, argv[2], NULL, NULL, 0);
+
+ if (argc < 4) {
+ pkg_print_info( pkg_hash_fetch_by_name_version(hash, "libc6", "2.2.3-2"), stdout);
+ /* for(i = 0; i < pkg_vec->len; i++)
+ pkg_print(pkg_vec->pkgs[i], stdout);
+ */
+ } else {
+ int i, j, k;
+ char **unresolved;
+
+ pkg_vec_t * dep_vec;
+ for (i = 3; i < argc; i++) {
+ pkg_vec = pkg_vec_fetch_by_name(hash, argv[i]);
+ if (pkg_vec == NULL) {
+ fprintf(stderr, "*** WARNING: Unknown package: %s\n\n", argv[i]);
+ continue;
+ }
+
+ for(j = 0; j < pkg_vec->len; j++){
+ pkg_print_info(pkg_vec->pkgs[j], stdout);
+ dep_vec = pkg_vec_alloc();
+ pkg_hash_fetch_unsatisfied_dependencies(&conf,
+ pkg_vec->pkgs[j],
+ dep_vec,
+ &unresolved);
+ if(dep_vec){
+ fprintf(stderr, "and the unsatisfied dependencies are:\n");
+ for(k = 0; k < dep_vec->len; k++){
+ fprintf(stderr, "%s version %s\n", dep_vec->pkgs[k]->name, dep_vec->pkgs[k]->version);
+ }
+ }
+
+ fputs("", stdout);
+
+ }
+ }
+ }
+
+ pkg_hash_deinit(hash);
+
+ return 0;
+}
diff --git a/src/tests/regress/.svn/all-wcprops b/src/tests/regress/.svn/all-wcprops
new file mode 100644
index 0000000..d83bc2c
--- /dev/null
+++ b/src/tests/regress/.svn/all-wcprops
@@ -0,0 +1,113 @@
+K 25
+svn:wc:ra_dav:version-url
+V 37
+/svn/!svn/ver/634/trunk/tests/regress
+END
+opk.py
+K 25
+svn:wc:ra_dav:version-url
+V 44
+/svn/!svn/ver/634/trunk/tests/regress/opk.py
+END
+issue31.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue31.py
+END
+issue50.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue50.py
+END
+issue51.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue51.py
+END
+cfg.py
+K 25
+svn:wc:ra_dav:version-url
+V 44
+/svn/!svn/ver/625/trunk/tests/regress/cfg.py
+END
+issue26.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue26.py
+END
+issue72.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue72.py
+END
+issue45.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue45.py
+END
+issue55.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue55.py
+END
+issue46.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue46.py
+END
+issue84.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/633/trunk/tests/regress/issue84.py
+END
+issue85.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/633/trunk/tests/regress/issue85.py
+END
+issue58.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue58.py
+END
+update_loses_autoinstalled_flag.py
+K 25
+svn:wc:ra_dav:version-url
+V 72
+/svn/!svn/ver/634/trunk/tests/regress/update_loses_autoinstalled_flag.py
+END
+issue79.py
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svn/!svn/ver/632/trunk/tests/regress/issue79.py
+END
+opkgcl.py
+K 25
+svn:wc:ra_dav:version-url
+V 47
+/svn/!svn/ver/634/trunk/tests/regress/opkgcl.py
+END
+filehash.py
+K 25
+svn:wc:ra_dav:version-url
+V 49
+/svn/!svn/ver/607/trunk/tests/regress/filehash.py
+END
+Makefile
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svn/!svn/ver/634/trunk/tests/regress/Makefile
+END
diff --git a/src/tests/regress/.svn/entries b/src/tests/regress/.svn/entries
new file mode 100644
index 0000000..511df3a
--- /dev/null
+++ b/src/tests/regress/.svn/entries
@@ -0,0 +1,640 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/tests/regress
+http://opkg.googlecode.com/svn
+
+
+
+2012-01-19T13:51:59.790020Z
+634
+pixdamix@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
+opk.py
+file
+
+
+
+
+2012-02-03T08:11:57.351042Z
+5042d77e53c77cee8b411296d50f963f
+2012-01-19T13:51:59.790020Z
+634
+pixdamix@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2877
+
+issue31.py
+file
+
+
+
+
+2012-02-03T08:11:57.351042Z
+5d1ac3bfa7788b1cf80301c1a3a92d04
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+508
+
+issue50.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+21fe4bed9f068d6c70d64e85a710d2e4
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+886
+
+issue51.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+825ba593541ddfbdb22dafb0264d35c4
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1519
+
+cfg.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+ef3d9028e718a965848082841b791e59
+2011-07-13T11:53:28.244081Z
+625
+pixdamix@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+105
+
+issue26.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+7eac6e442e578cf77ef822d00eddd20d
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+769
+
+issue72.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+18838b761e8fd311f2a1d0d4b15c843d
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1495
+
+issue45.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+c2a7947d78fad363733248d288d7e88d
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+649
+
+issue55.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+efceef4be0907165367b198c6450ea8b
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+530
+
+issue46.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+ebe87bdc7e69abcc75efa60b5d633311
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+906
+
+issue84.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+4c43bb8c7aa602242eca9a82690d5f19
+2011-10-27T04:53:01.363575Z
+633
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+882
+
+issue85.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+b2c52019fae7259e1b544b9e483cc05d
+2011-10-27T04:53:01.363575Z
+633
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+502
+
+issue58.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+4e7dab61a69f31a519f5d343d1e612c0
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+588
+
+update_loses_autoinstalled_flag.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+3f8e7328cd8cdb9b6edaac81c0c190fe
+2012-01-19T13:51:59.790020Z
+634
+pixdamix@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1101
+
+issue79.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+af632f0199342dc3c0362631aafe884d
+2011-10-23T23:42:50.670289Z
+632
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+663
+
+opkgcl.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+624d2252b119c9b07de516629e6d546b
+2012-01-19T13:51:59.790020Z
+634
+pixdamix@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1762
+
+filehash.py
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+09c39129cb0ccb6491bcaa104124a25d
+2011-02-21T04:45:33.007731Z
+607
+graham.gower@gmail.com
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+886
+
+Makefile
+file
+
+
+
+
+2012-02-03T08:11:57.355042Z
+9a157e2971d52870d9bb49c61ad74603
+2012-01-19T13:51:59.790020Z
+634
+pixdamix@gmail.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+356
+
diff --git a/src/tests/regress/.svn/prop-base/filehash.py.svn-base b/src/tests/regress/.svn/prop-base/filehash.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/filehash.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue26.py.svn-base b/src/tests/regress/.svn/prop-base/issue26.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue26.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue31.py.svn-base b/src/tests/regress/.svn/prop-base/issue31.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue31.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue45.py.svn-base b/src/tests/regress/.svn/prop-base/issue45.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue45.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue46.py.svn-base b/src/tests/regress/.svn/prop-base/issue46.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue46.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue50.py.svn-base b/src/tests/regress/.svn/prop-base/issue50.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue50.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue51.py.svn-base b/src/tests/regress/.svn/prop-base/issue51.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue51.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue55.py.svn-base b/src/tests/regress/.svn/prop-base/issue55.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue55.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue58.py.svn-base b/src/tests/regress/.svn/prop-base/issue58.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue58.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue72.py.svn-base b/src/tests/regress/.svn/prop-base/issue72.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue72.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue79.py.svn-base b/src/tests/regress/.svn/prop-base/issue79.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue79.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue84.py.svn-base b/src/tests/regress/.svn/prop-base/issue84.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue84.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/issue85.py.svn-base b/src/tests/regress/.svn/prop-base/issue85.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/issue85.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/prop-base/opkgcl.py.svn-base b/src/tests/regress/.svn/prop-base/opkgcl.py.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/tests/regress/.svn/prop-base/opkgcl.py.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/tests/regress/.svn/text-base/Makefile.svn-base b/src/tests/regress/.svn/text-base/Makefile.svn-base
new file mode 100644
index 0000000..0accb31
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,15 @@
+PYTHON=/usr/bin/python3
+REGRESSION_TESTS=issue26.py issue31.py issue45.py issue46.py \
+ issue50.py issue51.py issue55.py issue58.py \
+ issue72.py issue79.py issue84.py issue85.py \
+ filehash.py \
+ update_loses_autoinstalled_flag.py
+
+regress:
+ @for test in $(REGRESSION_TESTS); do \
+ echo $$test; \
+ $(PYTHON) $$test; \
+ done
+
+clean:
+ rm -f *.pyc
diff --git a/src/tests/regress/.svn/text-base/cfg.py.svn-base b/src/tests/regress/.svn/text-base/cfg.py.svn-base
new file mode 100644
index 0000000..6f78996
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/cfg.py.svn-base
@@ -0,0 +1,5 @@
+import os
+
+opkdir = "/tmp/opk"
+offline_root = "/tmp/opkg"
+opkgcl = os.path.realpath("../../src/opkg-cl")
diff --git a/src/tests/regress/.svn/text-base/filehash.py.svn-base b/src/tests/regress/.svn/text-base/filehash.py.svn-base
new file mode 100644
index 0000000..e6cbe62
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/filehash.py.svn-base
@@ -0,0 +1,35 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+open("asdf", "w").close()
+a = opk.Opk(Package="a", Version="1.0", Architecture="all")
+a.write(data_files=["asdf"])
+b = opk.Opk(Package="b", Version="1.0", Architecture="all")
+b.write(data_files=["asdf"])
+os.unlink("asdf")
+opkgcl.install("a_1.0_all.opk")
+
+if not opkgcl.is_installed("a"):
+ print(__file__, ": Package 'a' not installed.")
+ exit(False)
+
+if not os.path.exists("{}/asdf".format(cfg.offline_root)):
+ print(__file__, ": asdf not created.")
+ exit(False)
+
+opkgcl.install("b_1.0_all.opk", "--force-overwrite")
+
+if "{}/asdf".format(cfg.offline_root) not in opkgcl.files("b"):
+ print(__file__, ": asdf not claimed by ``b''.")
+ exit(False)
+
+if "{}/asdf".format(cfg.offline_root) in opkgcl.files("a"):
+ print(__file__, ": asdf is still claimed by ``a''.")
+ exit(False)
+
+opkgcl.remove("b")
+opkgcl.remove("a")
diff --git a/src/tests/regress/.svn/text-base/issue26.py.svn-base b/src/tests/regress/.svn/text-base/issue26.py.svn-base
new file mode 100644
index 0000000..dd4ef92
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue26.py.svn-base
@@ -0,0 +1,35 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Version="2.0")
+o.write_opk()
+o.write_list()
+
+# older version, not in Packages list
+a1 = opk.Opk(Package="a", Version="1.0")
+a1.write()
+
+opkgcl.update()
+
+# install v2 from repository
+opkgcl.install("a")
+if not opkgcl.is_installed("a", "2.0"):
+ print(__file__, ": Package 'a_2.0' not installed.")
+ exit(False)
+
+opkgcl.install("a_1.0_all.opk", "--force-downgrade")
+if not opkgcl.is_installed("a", "1.0"):
+ print(__file__, ": Package 'a_1.0' not installed (1).")
+ exit(False)
+
+opkgcl.install("a_1.0_all.opk", "--force-downgrade")
+if not opkgcl.is_installed("a", "1.0"):
+ print(__file__, ": Package 'a_1.0' not installed (2).")
+ exit(False)
+
+opkgcl.remove("a")
diff --git a/src/tests/regress/.svn/text-base/issue31.py.svn-base b/src/tests/regress/.svn/text-base/issue31.py.svn-base
new file mode 100644
index 0000000..42e51e3
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue31.py.svn-base
@@ -0,0 +1,25 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Depends="b")
+o.add(Package="b", Depends="c")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+opkgcl.install("a")
+if opkgcl.is_installed("a"):
+ print(__file__, ": Package 'a' installed, despite dependency "
+ "upon a package with an unresolved dependency.")
+ exit(False)
+
+if opkgcl.is_installed("b"):
+ print(__file__, ": Package 'b' installed, "
+ "despite unresolved dependency.")
+ exit(False)
diff --git a/src/tests/regress/.svn/text-base/issue45.py.svn-base b/src/tests/regress/.svn/text-base/issue45.py.svn-base
new file mode 100644
index 0000000..30735f9
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue45.py.svn-base
@@ -0,0 +1,33 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Depends="b")
+o.add(Package="b")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+(status, output) = opkgcl.opkgcl("install --force-postinstall a")
+ln_a = output.find("Configuring a")
+ln_b = output.find("Configuring b")
+
+if ln_a == -1:
+ print(__file__, ": Didn't see package 'a' get configured.")
+ exit(False)
+
+if ln_b == -1:
+ print(__file__, ": Didn't see package 'b' get configured.")
+ exit(False)
+
+if ln_a < ln_b:
+ print(__file__, ": Packages 'a' and 'b' configured in wrong order.")
+ exit(False)
+
+opkgcl.remove("a")
+opkgcl.remove("b")
diff --git a/src/tests/regress/.svn/text-base/issue46.py.svn-base b/src/tests/regress/.svn/text-base/issue46.py.svn-base
new file mode 100644
index 0000000..ec56941
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue46.py.svn-base
@@ -0,0 +1,39 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Version="1.0", Recommends="b")
+o.add(Package="b", Version="2.0")
+o.write_opk()
+o.write_list()
+
+# prime the status file so 'b' is not installed as a recommendation
+status_filename = "{}/usr/lib/opkg/status".format(cfg.offline_root)
+f = open(status_filename, "w")
+f.write("Package: b\n")
+f.write("Version: 1.0\n")
+f.write("Architecture: all\n")
+f.write("Status: deinstall hold not-installed\n")
+f.close()
+
+opkgcl.update()
+
+opkgcl.install("a")
+if opkgcl.is_installed("b"):
+ print(__file__, ": Package 'b' installed despite "
+ "deinstall/hold status.")
+ exit(False)
+
+opkgcl.remove("a")
+opkgcl.install("a")
+if opkgcl.is_installed("b"):
+ print(__file__, ": Package 'b' installed - deinstall/hold status "
+ "not retained.")
+ exit(False)
+
+opkgcl.remove("a")
+open(status_filename, "w").close()
diff --git a/src/tests/regress/.svn/text-base/issue50.py.svn-base b/src/tests/regress/.svn/text-base/issue50.py.svn-base
new file mode 100644
index 0000000..19897b4
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue50.py.svn-base
@@ -0,0 +1,43 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+open("foo", "w").close()
+a1 = opk.Opk(Package="a", Version="1.0")
+a1.write(data_files=["foo"])
+
+opkgcl.install("a_1.0_all.opk")
+
+o = opk.OpkGroup()
+a2 = opk.Opk(Package="a", Version="2.0", Depends="b")
+a2.write()
+b1 = opk.Opk(Package="b", Version="1.0")
+b1.write(data_files=["foo"])
+o.opk_list.append(a2)
+o.opk_list.append(b1)
+o.write_list()
+
+os.unlink("foo")
+
+opkgcl.update()
+opkgcl.upgrade()
+
+if not opkgcl.is_installed("a", "2.0"):
+ print(__file__, ": Package 'a_2.0' not installed.")
+ exit(False)
+
+foo_fullpath = "{}/foo".format(cfg.offline_root)
+
+if not os.path.exists(foo_fullpath):
+ print(__file__, ": File 'foo' incorrectly orphaned.")
+ exit(False)
+
+if not foo_fullpath in opkgcl.files("b"):
+ print(__file__, ": Package 'b' does not own file 'foo'.")
+ exit(False)
+
+opkgcl.remove("a")
+opkgcl.remove("b")
diff --git a/src/tests/regress/.svn/text-base/issue51.py.svn-base b/src/tests/regress/.svn/text-base/issue51.py.svn-base
new file mode 100644
index 0000000..9849dbc
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue51.py.svn-base
@@ -0,0 +1,70 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+open("foo", "w").close()
+a1 = opk.Opk(Package="a")
+a1.write(data_files=["foo"])
+os.rename("a_1.0_all.opk", "a_with_foo.opk")
+
+opkgcl.install("a_with_foo.opk")
+
+# ----
+opkgcl.install("a_with_foo.opk")
+
+open("bar", "w").close()
+o = opk.OpkGroup()
+a2 = opk.Opk(Package="a")
+a2.write(data_files=["foo", "bar"])
+o.opk_list.append(a2)
+o.write_list()
+
+os.unlink("foo")
+os.unlink("bar")
+
+opkgcl.update()
+opkgcl.install("a", "--force-reinstall")
+
+foo_fullpath = "{}/foo".format(cfg.offline_root)
+bar_fullpath = "{}/bar".format(cfg.offline_root)
+
+if not os.path.exists(foo_fullpath) or not os.path.exists(bar_fullpath):
+ print(__file__, ": Files foo and/or bar are missing.")
+ exit(False)
+
+a_files = opkgcl.files("a")
+if not foo_fullpath in a_files or not bar_fullpath in a_files:
+ print(__file__, ": Package 'a' does not own foo and/or bar.")
+ exit(False)
+
+opkgcl.remove("a")
+
+if os.path.exists(foo_fullpath) or os.path.exists(bar_fullpath):
+ print(__file__, ": Files foo and/or bar still exist "
+ "after removal of package 'a'.")
+ exit(False)
+
+# ----
+o = opk.OpkGroup()
+a2 = opk.Opk(Package="a")
+a2.write()
+o.opk_list.append(a2)
+o.write_list()
+
+
+opkgcl.update()
+
+opkgcl.install("a", "--force-reinstall")
+
+if os.path.exists(foo_fullpath):
+ print(__file__, ": File 'foo' not orphaned as it should be.")
+ exit(False)
+
+if foo_fullpath in opkgcl.files("a"):
+ print(__file__, ": Package 'a' incorrectly owns file 'foo'.")
+ exit(False)
+
+opkgcl.remove("a")
diff --git a/src/tests/regress/.svn/text-base/issue55.py.svn-base b/src/tests/regress/.svn/text-base/issue55.py.svn-base
new file mode 100644
index 0000000..8628306
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue55.py.svn-base
@@ -0,0 +1,25 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+long_filename = 110*"a"
+
+os.symlink(long_filename, "linky")
+a = opk.Opk(Package="a")
+a.write(data_files=["linky"])
+os.unlink("linky")
+opkgcl.install("a_1.0_all.opk")
+
+if not opkgcl.is_installed("a"):
+ print(__file__, ": Package 'a' not installed.")
+ exit(False)
+
+if not os.path.lexists("{}/linky".format(cfg.offline_root)):
+ print(__file__, ": symlink to file with a name longer than 100 "
+ "characters not created.")
+ exit(False)
+
+opkgcl.remove("a")
diff --git a/src/tests/regress/.svn/text-base/issue58.py.svn-base b/src/tests/regress/.svn/text-base/issue58.py.svn-base
new file mode 100644
index 0000000..72a1854
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue58.py.svn-base
@@ -0,0 +1,31 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Recommends="b")
+o.add(Package="b")
+o.add(Package="c", Recommends="b")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+opkgcl.install("a")
+opkgcl.install("c")
+
+opkgcl.remove("a", "--autoremove")
+if not opkgcl.is_installed("b"):
+ print(__file__, ": Pacakge 'b' orphaned despite remaining "
+ "recommending package 'c'.")
+ exit(False)
+
+opkgcl.remove("c", "--autoremove")
+if opkgcl.is_installed("b"):
+ print(__file__, ": Recommended package 'b' not autoremoved.")
+ exit(False)
+
+
diff --git a/src/tests/regress/.svn/text-base/issue72.py.svn-base b/src/tests/regress/.svn/text-base/issue72.py.svn-base
new file mode 100644
index 0000000..d0c511b
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue72.py.svn-base
@@ -0,0 +1,52 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+long_dir = 110*"a"
+long_b = 110*"b"
+long_filename = long_dir + "/"+ long_b
+long_filename2 = long_dir + "/" + 110*"c"
+
+os.mkdir(long_dir)
+open(long_filename, "w").close()
+os.symlink(long_b, long_filename2)
+a = opk.Opk(Package="a")
+a.write(data_files=[long_dir, long_filename, long_filename2])
+os.unlink(long_filename)
+os.unlink(long_filename2)
+os.rmdir(long_dir)
+opkgcl.install("a_1.0_all.opk")
+
+if not opkgcl.is_installed("a"):
+ print(__file__, ": Package 'a' not installed.")
+ exit(False)
+
+if not os.path.exists("{}/{}".format(cfg.offline_root, long_dir)):
+ print(__file__, ": dir with name longer than 100 "
+ "characters not created.")
+ exit(False)
+
+if not os.path.exists("{}/{}".format(cfg.offline_root, long_filename)):
+ print(__file__, ": file with a name longer than 100 characters, "
+ "in dir with name longer than 100 characters, "
+ "not created.")
+ exit(False)
+
+if not os.path.lexists("{}/{}".format(cfg.offline_root, long_filename2)):
+ print(__file__, ": symlink with a name longer than 100 characters, "
+ "pointing at a file with a name longer than "
+ "100 characters,"
+ "in dir with name longer than 100 characters, "
+ "not created.")
+ exit(False)
+
+linky = os.path.realpath("{}/{}".format(cfg.offline_root, long_filename2))
+linky_dst = "{}/{}".format(cfg.offline_root, long_filename)
+if linky != linky_dst:
+ print(__file__, ": symlink path truncated.")
+ exit(False)
+
+opkgcl.remove("a")
diff --git a/src/tests/regress/.svn/text-base/issue79.py.svn-base b/src/tests/regress/.svn/text-base/issue79.py.svn-base
new file mode 100644
index 0000000..30ba201
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue79.py.svn-base
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Version="1.0", Depends="b")
+o.add(Package="b", Version="1.0")
+o.add(Package="c", Version="1.0", Depends="b")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+opkgcl.install("a")
+opkgcl.install("c")
+
+opkgcl.flag_unpacked("a")
+
+o = opk.OpkGroup()
+o.add(Package="a", Version="1.0", Depends="b")
+o.add(Package="b", Version="1.0")
+o.add(Package="c", Version="2.0")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+opkgcl.upgrade("--autoremove")
+
+if not opkgcl.is_installed("b", "1.0"):
+ print("b has been removed even though a still depends on it")
+ exit(False)
diff --git a/src/tests/regress/.svn/text-base/issue84.py.svn-base b/src/tests/regress/.svn/text-base/issue84.py.svn-base
new file mode 100644
index 0000000..1f5d43e
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue84.py.svn-base
@@ -0,0 +1,45 @@
+#!/usr/bin/python3
+
+import opk, cfg, opkgcl
+
+def cleanup():
+ opkgcl.remove("a1")
+ opkgcl.remove("b1")
+ opkgcl.remove("a")
+ opkgcl.remove("b")
+ opkgcl.remove('c')
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Provides="v", Depends="a1")
+o.add(Package="b", Provides="v", Depends="b1")
+o.add(Package="c", Depends="v")
+o.add(Package="a1")
+o.add(Package="b1")
+
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+# install ``a1`` directly
+opkgcl.install("a1_1.0_all.opk")
+if not opkgcl.is_installed("a1"):
+ print(__file__, ": package ``a1'' not installed.")
+ cleanup()
+ exit(False)
+
+# install ``c'' from repository
+opkgcl.install("c")
+if not opkgcl.is_installed("c"):
+ print(__file__, ": package ``c'' not installed.")
+ cleanup()
+ exit(False)
+
+if opkgcl.is_installed("b1"):
+ print(__file__, ": package ``b1'' is installed, but should not be.")
+ cleanup()
+ exit(False)
+
+cleanup()
diff --git a/src/tests/regress/.svn/text-base/issue85.py.svn-base b/src/tests/regress/.svn/text-base/issue85.py.svn-base
new file mode 100644
index 0000000..3250075
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/issue85.py.svn-base
@@ -0,0 +1,29 @@
+#!/usr/bin/python3
+
+import opk, cfg, opkgcl
+
+def cleanup():
+ opkgcl.remove("a")
+ opkgcl.remove("b")
+ opkgcl.remove('c')
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Provides="v")
+o.add(Package="b", Provides="v", Depends="b_nonexistant")
+o.add(Package="c", Depends="v")
+
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+# install ``c'' from repository
+opkgcl.install("c")
+if not opkgcl.is_installed("c"):
+ print(__file__, ": package ``c'' not installed.")
+ cleanup()
+ exit(False)
+
+cleanup()
diff --git a/src/tests/regress/.svn/text-base/opk.py.svn-base b/src/tests/regress/.svn/text-base/opk.py.svn-base
new file mode 100644
index 0000000..f96037e
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/opk.py.svn-base
@@ -0,0 +1,111 @@
+import tarfile, os
+import cfg
+
+class Opk:
+ valid_control_fields = ["Package", "Version", "Depends", "Provides",\
+ "Replaces", "Conflicts", "Suggests", "Recommends",\
+ "Section", "Architecture", "Maintainer", "MD5Sum",\
+ "Size", "InstalledSize", "Filename", "Source",\
+ "Description", "OE", "Homepage", "Priority",\
+ "Conffiles"]
+
+ def __init__(self, **control):
+ for k in control.keys():
+ if k not in self.valid_control_fields:
+ raise Exception("Invalid control field: "
+ "{}".format(k))
+ if "Package" not in control.keys():
+ print("Cannot create opk without Package name.\n")
+ return None
+ if "Architecture" not in control.keys():
+ control["Architecture"] = "all"
+ if "Version" not in control.keys():
+ control["Version"] = "1.0"
+ self.control = control
+
+ def write(self, tar_not_ar=False, data_files=None):
+ filename = "{Package}_{Version}_{Architecture}.opk"\
+ .format(**self.control)
+ if os.path.exists(filename):
+ os.unlink(filename)
+ if os.path.exists("control"):
+ os.unlink("control")
+ if os.path.exists("control.tar.gz"):
+ os.unlink("control.tar.gz")
+ if os.path.exists("data.tar.gz"):
+ os.unlink("data.tar.gz")
+
+ f = open("control", "w")
+ for k in self.control.keys():
+ f.write("{}: {}\n".format(k, self.control[k]))
+ f.close()
+
+ tar = tarfile.open("control.tar.gz", "w:gz")
+ tar.add("control")
+ tar.close()
+
+ tar = tarfile.open("data.tar.gz", "w:gz")
+ if data_files:
+ for df in data_files:
+ tar.add(df)
+ tar.close()
+
+
+ if tar_not_ar:
+ tar = tarfile.open(filename, "w:gz")
+ tar.add("control.tar.gz")
+ tar.add("data.tar.gz")
+ tar.close()
+ else:
+ os.system("ar q {} control.tar.gz data.tar.gz \
+ 2>/dev/null".format(filename))
+
+ os.unlink("control")
+ os.unlink("control.tar.gz")
+ os.unlink("data.tar.gz")
+
+class OpkGroup:
+ def __init__(self):
+ self.opk_list = []
+
+ def add(self, **control):
+ self.opk_list.append(Opk(**control))
+
+ def addOpk(self, opk):
+ self.opk_list.append(opk)
+
+ def write_opk(self, tar_not_ar=False):
+ for o in self.opk_list:
+ o.write(tar_not_ar)
+
+ def write_list(self, filename="Packages"):
+ f = open(filename, "w")
+ for opk in self.opk_list:
+ for k in opk.control.keys():
+ f.write("{}: {}\n".format(k, opk.control[k]))
+ f.write("Filename: {Package}_{Version}_{Architecture}"
+ ".opk\n".format(**opk.control))
+ f.write("\n")
+ f.close()
+
+
+def regress_init():
+ """
+ Initialisation and sanity checking.
+ """
+
+ if not os.access(cfg.opkgcl, os.X_OK):
+ print("Cannot exec {}".format(cfg.opkgcl))
+ exit(False)
+
+ os.chdir(cfg.opkdir)
+
+ os.system("rm -fr {}".format(cfg.offline_root))
+
+ os.makedirs("{}/usr/lib/opkg".format(cfg.offline_root))
+ os.makedirs("{}/etc/opkg".format(cfg.offline_root))
+
+ f = open("{}/etc/opkg/opkg.conf".format(cfg.offline_root), "w")
+ f.write("arch all 1\n")
+ f.write("src test file:{}\n".format(cfg.opkdir))
+ f.close()
diff --git a/src/tests/regress/.svn/text-base/opkgcl.py.svn-base b/src/tests/regress/.svn/text-base/opkgcl.py.svn-base
new file mode 100644
index 0000000..47e7dd3
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/opkgcl.py.svn-base
@@ -0,0 +1,64 @@
+#!/usr/bin/python3
+
+import os, subprocess
+import cfg
+
+def opkgcl(opkg_args):
+ cmd = "{} -o {} {}".format(cfg.opkgcl, cfg.offline_root, opkg_args)
+ #print(cmd)
+ return subprocess.getstatusoutput(cmd)
+
+def install(pkg_name, flags=""):
+ return opkgcl("{} install {}".format(flags, pkg_name))[0]
+
+def remove(pkg_name, flags=""):
+ return opkgcl("{} remove {}".format(flags, pkg_name))[0]
+
+def update():
+ return opkgcl("update")[0]
+
+def upgrade(params=None):
+ if params:
+ opkgcl("upgrade {}".format(params))[0]
+ else:
+ return opkgcl("upgrade")[0]
+
+def files(pkg_name):
+ output = opkgcl("files {}".format(pkg_name))[1]
+ return output.split("\n")[1:]
+
+
+def flag_unpacked(pkg_name):
+ out = opkgcl("flag unpacked {}".format(pkg_name))
+ return out == "Setting flags for package {} to unpacked.".format(pkg_name)
+
+def is_installed(pkg_name, version=None):
+ out = opkgcl("list_installed {}".format(pkg_name))[1]
+ if len(out) == 0 or out.split()[0] != pkg_name:
+ return False
+ if version and out.split()[2] != version:
+ return False
+ if not os.path.exists("{}/usr/lib/opkg/info/{}.control"\
+ .format(cfg.offline_root, pkg_name)):
+ return False
+ return True
+
+def is_autoinstalled(pkg_name):
+ status_path = "{}/usr/lib/opkg/status".format(cfg.offline_root)
+ if not os.path.exists(status_path):
+ return False
+ status_file = open(status_path, "r")
+ status = status_file.read()
+ status_file.close()
+ index_start = status.find("Package: {}".format(pkg_name))
+ if index_start < 0:
+ return False
+ index_end = status.find("\n\n", index_start)
+ return status.find("Auto-Installed: yes", index_start, index_end) >= 0
+
+
+if __name__ == '__main__':
+ import sys
+ (status, output) = opkgcl(" ".join(sys.argv[1:]))
+ print(output)
+ exit(status)
diff --git a/src/tests/regress/.svn/text-base/update_loses_autoinstalled_flag.py.svn-base b/src/tests/regress/.svn/text-base/update_loses_autoinstalled_flag.py.svn-base
new file mode 100644
index 0000000..5ae030c
--- /dev/null
+++ b/src/tests/regress/.svn/text-base/update_loses_autoinstalled_flag.py.svn-base
@@ -0,0 +1,63 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+bug = True
+
+opk.regress_init()
+
+open("asdf", "w").close()
+a = opk.Opk(Package="a", Version="1.0", Depends="b")
+a.write()
+b = opk.Opk(Package="b", Version="1.0")
+b.write(data_files=["asdf"])
+
+o = opk.OpkGroup()
+o.addOpk(a)
+o.addOpk(b)
+o.write_list()
+
+opkgcl.update()
+opkgcl.install("a")
+
+if not opkgcl.is_autoinstalled("b"):
+ print("b is not autoinstalled")
+ exit(False)
+
+if (bug):
+ a = opk.Opk(Package="a", Version="2.0", Depends="b")
+ a.write()
+ b = opk.Opk(Package="b", Version="2.0")
+ b.write(data_files=["asdf"])
+
+ o = opk.OpkGroup()
+ o.addOpk(a)
+ o.addOpk(b)
+ o.write_list()
+
+ opkgcl.update()
+ opkgcl.upgrade();
+
+ if not opkgcl.is_autoinstalled("b"):
+ print("b is not autoinstalled anymore")
+ exit(False)
+
+a = opk.Opk(Package="a", Version="3.0")
+a.write(data_files=["asdf"])
+os.unlink("asdf")
+
+o = opk.OpkGroup()
+o.addOpk(a)
+o.write_list()
+
+opkgcl.update()
+opkgcl.upgrade();
+
+if opkgcl.is_installed("b", "2.0"):
+ print("b is still installed")
+ exit(False)
+
+if not opkgcl.is_installed("a", "3.0"):
+ print("a is not installed")
+ exit(False)
diff --git a/src/tests/regress/Makefile b/src/tests/regress/Makefile
new file mode 100644
index 0000000..0accb31
--- /dev/null
+++ b/src/tests/regress/Makefile
@@ -0,0 +1,15 @@
+PYTHON=/usr/bin/python3
+REGRESSION_TESTS=issue26.py issue31.py issue45.py issue46.py \
+ issue50.py issue51.py issue55.py issue58.py \
+ issue72.py issue79.py issue84.py issue85.py \
+ filehash.py \
+ update_loses_autoinstalled_flag.py
+
+regress:
+ @for test in $(REGRESSION_TESTS); do \
+ echo $$test; \
+ $(PYTHON) $$test; \
+ done
+
+clean:
+ rm -f *.pyc
diff --git a/src/tests/regress/cfg.py b/src/tests/regress/cfg.py
new file mode 100644
index 0000000..6f78996
--- /dev/null
+++ b/src/tests/regress/cfg.py
@@ -0,0 +1,5 @@
+import os
+
+opkdir = "/tmp/opk"
+offline_root = "/tmp/opkg"
+opkgcl = os.path.realpath("../../src/opkg-cl")
diff --git a/src/tests/regress/filehash.py b/src/tests/regress/filehash.py
new file mode 100755
index 0000000..e6cbe62
--- /dev/null
+++ b/src/tests/regress/filehash.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+open("asdf", "w").close()
+a = opk.Opk(Package="a", Version="1.0", Architecture="all")
+a.write(data_files=["asdf"])
+b = opk.Opk(Package="b", Version="1.0", Architecture="all")
+b.write(data_files=["asdf"])
+os.unlink("asdf")
+opkgcl.install("a_1.0_all.opk")
+
+if not opkgcl.is_installed("a"):
+ print(__file__, ": Package 'a' not installed.")
+ exit(False)
+
+if not os.path.exists("{}/asdf".format(cfg.offline_root)):
+ print(__file__, ": asdf not created.")
+ exit(False)
+
+opkgcl.install("b_1.0_all.opk", "--force-overwrite")
+
+if "{}/asdf".format(cfg.offline_root) not in opkgcl.files("b"):
+ print(__file__, ": asdf not claimed by ``b''.")
+ exit(False)
+
+if "{}/asdf".format(cfg.offline_root) in opkgcl.files("a"):
+ print(__file__, ": asdf is still claimed by ``a''.")
+ exit(False)
+
+opkgcl.remove("b")
+opkgcl.remove("a")
diff --git a/src/tests/regress/issue26.py b/src/tests/regress/issue26.py
new file mode 100755
index 0000000..dd4ef92
--- /dev/null
+++ b/src/tests/regress/issue26.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Version="2.0")
+o.write_opk()
+o.write_list()
+
+# older version, not in Packages list
+a1 = opk.Opk(Package="a", Version="1.0")
+a1.write()
+
+opkgcl.update()
+
+# install v2 from repository
+opkgcl.install("a")
+if not opkgcl.is_installed("a", "2.0"):
+ print(__file__, ": Package 'a_2.0' not installed.")
+ exit(False)
+
+opkgcl.install("a_1.0_all.opk", "--force-downgrade")
+if not opkgcl.is_installed("a", "1.0"):
+ print(__file__, ": Package 'a_1.0' not installed (1).")
+ exit(False)
+
+opkgcl.install("a_1.0_all.opk", "--force-downgrade")
+if not opkgcl.is_installed("a", "1.0"):
+ print(__file__, ": Package 'a_1.0' not installed (2).")
+ exit(False)
+
+opkgcl.remove("a")
diff --git a/src/tests/regress/issue31.py b/src/tests/regress/issue31.py
new file mode 100755
index 0000000..42e51e3
--- /dev/null
+++ b/src/tests/regress/issue31.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Depends="b")
+o.add(Package="b", Depends="c")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+opkgcl.install("a")
+if opkgcl.is_installed("a"):
+ print(__file__, ": Package 'a' installed, despite dependency "
+ "upon a package with an unresolved dependency.")
+ exit(False)
+
+if opkgcl.is_installed("b"):
+ print(__file__, ": Package 'b' installed, "
+ "despite unresolved dependency.")
+ exit(False)
diff --git a/src/tests/regress/issue45.py b/src/tests/regress/issue45.py
new file mode 100755
index 0000000..30735f9
--- /dev/null
+++ b/src/tests/regress/issue45.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Depends="b")
+o.add(Package="b")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+(status, output) = opkgcl.opkgcl("install --force-postinstall a")
+ln_a = output.find("Configuring a")
+ln_b = output.find("Configuring b")
+
+if ln_a == -1:
+ print(__file__, ": Didn't see package 'a' get configured.")
+ exit(False)
+
+if ln_b == -1:
+ print(__file__, ": Didn't see package 'b' get configured.")
+ exit(False)
+
+if ln_a < ln_b:
+ print(__file__, ": Packages 'a' and 'b' configured in wrong order.")
+ exit(False)
+
+opkgcl.remove("a")
+opkgcl.remove("b")
diff --git a/src/tests/regress/issue46.py b/src/tests/regress/issue46.py
new file mode 100755
index 0000000..ec56941
--- /dev/null
+++ b/src/tests/regress/issue46.py
@@ -0,0 +1,39 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Version="1.0", Recommends="b")
+o.add(Package="b", Version="2.0")
+o.write_opk()
+o.write_list()
+
+# prime the status file so 'b' is not installed as a recommendation
+status_filename = "{}/usr/lib/opkg/status".format(cfg.offline_root)
+f = open(status_filename, "w")
+f.write("Package: b\n")
+f.write("Version: 1.0\n")
+f.write("Architecture: all\n")
+f.write("Status: deinstall hold not-installed\n")
+f.close()
+
+opkgcl.update()
+
+opkgcl.install("a")
+if opkgcl.is_installed("b"):
+ print(__file__, ": Package 'b' installed despite "
+ "deinstall/hold status.")
+ exit(False)
+
+opkgcl.remove("a")
+opkgcl.install("a")
+if opkgcl.is_installed("b"):
+ print(__file__, ": Package 'b' installed - deinstall/hold status "
+ "not retained.")
+ exit(False)
+
+opkgcl.remove("a")
+open(status_filename, "w").close()
diff --git a/src/tests/regress/issue50.py b/src/tests/regress/issue50.py
new file mode 100755
index 0000000..19897b4
--- /dev/null
+++ b/src/tests/regress/issue50.py
@@ -0,0 +1,43 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+open("foo", "w").close()
+a1 = opk.Opk(Package="a", Version="1.0")
+a1.write(data_files=["foo"])
+
+opkgcl.install("a_1.0_all.opk")
+
+o = opk.OpkGroup()
+a2 = opk.Opk(Package="a", Version="2.0", Depends="b")
+a2.write()
+b1 = opk.Opk(Package="b", Version="1.0")
+b1.write(data_files=["foo"])
+o.opk_list.append(a2)
+o.opk_list.append(b1)
+o.write_list()
+
+os.unlink("foo")
+
+opkgcl.update()
+opkgcl.upgrade()
+
+if not opkgcl.is_installed("a", "2.0"):
+ print(__file__, ": Package 'a_2.0' not installed.")
+ exit(False)
+
+foo_fullpath = "{}/foo".format(cfg.offline_root)
+
+if not os.path.exists(foo_fullpath):
+ print(__file__, ": File 'foo' incorrectly orphaned.")
+ exit(False)
+
+if not foo_fullpath in opkgcl.files("b"):
+ print(__file__, ": Package 'b' does not own file 'foo'.")
+ exit(False)
+
+opkgcl.remove("a")
+opkgcl.remove("b")
diff --git a/src/tests/regress/issue51.py b/src/tests/regress/issue51.py
new file mode 100755
index 0000000..9849dbc
--- /dev/null
+++ b/src/tests/regress/issue51.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+open("foo", "w").close()
+a1 = opk.Opk(Package="a")
+a1.write(data_files=["foo"])
+os.rename("a_1.0_all.opk", "a_with_foo.opk")
+
+opkgcl.install("a_with_foo.opk")
+
+# ----
+opkgcl.install("a_with_foo.opk")
+
+open("bar", "w").close()
+o = opk.OpkGroup()
+a2 = opk.Opk(Package="a")
+a2.write(data_files=["foo", "bar"])
+o.opk_list.append(a2)
+o.write_list()
+
+os.unlink("foo")
+os.unlink("bar")
+
+opkgcl.update()
+opkgcl.install("a", "--force-reinstall")
+
+foo_fullpath = "{}/foo".format(cfg.offline_root)
+bar_fullpath = "{}/bar".format(cfg.offline_root)
+
+if not os.path.exists(foo_fullpath) or not os.path.exists(bar_fullpath):
+ print(__file__, ": Files foo and/or bar are missing.")
+ exit(False)
+
+a_files = opkgcl.files("a")
+if not foo_fullpath in a_files or not bar_fullpath in a_files:
+ print(__file__, ": Package 'a' does not own foo and/or bar.")
+ exit(False)
+
+opkgcl.remove("a")
+
+if os.path.exists(foo_fullpath) or os.path.exists(bar_fullpath):
+ print(__file__, ": Files foo and/or bar still exist "
+ "after removal of package 'a'.")
+ exit(False)
+
+# ----
+o = opk.OpkGroup()
+a2 = opk.Opk(Package="a")
+a2.write()
+o.opk_list.append(a2)
+o.write_list()
+
+
+opkgcl.update()
+
+opkgcl.install("a", "--force-reinstall")
+
+if os.path.exists(foo_fullpath):
+ print(__file__, ": File 'foo' not orphaned as it should be.")
+ exit(False)
+
+if foo_fullpath in opkgcl.files("a"):
+ print(__file__, ": Package 'a' incorrectly owns file 'foo'.")
+ exit(False)
+
+opkgcl.remove("a")
diff --git a/src/tests/regress/issue55.py b/src/tests/regress/issue55.py
new file mode 100755
index 0000000..8628306
--- /dev/null
+++ b/src/tests/regress/issue55.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+long_filename = 110*"a"
+
+os.symlink(long_filename, "linky")
+a = opk.Opk(Package="a")
+a.write(data_files=["linky"])
+os.unlink("linky")
+opkgcl.install("a_1.0_all.opk")
+
+if not opkgcl.is_installed("a"):
+ print(__file__, ": Package 'a' not installed.")
+ exit(False)
+
+if not os.path.lexists("{}/linky".format(cfg.offline_root)):
+ print(__file__, ": symlink to file with a name longer than 100 "
+ "characters not created.")
+ exit(False)
+
+opkgcl.remove("a")
diff --git a/src/tests/regress/issue58.py b/src/tests/regress/issue58.py
new file mode 100755
index 0000000..72a1854
--- /dev/null
+++ b/src/tests/regress/issue58.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Recommends="b")
+o.add(Package="b")
+o.add(Package="c", Recommends="b")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+opkgcl.install("a")
+opkgcl.install("c")
+
+opkgcl.remove("a", "--autoremove")
+if not opkgcl.is_installed("b"):
+ print(__file__, ": Pacakge 'b' orphaned despite remaining "
+ "recommending package 'c'.")
+ exit(False)
+
+opkgcl.remove("c", "--autoremove")
+if opkgcl.is_installed("b"):
+ print(__file__, ": Recommended package 'b' not autoremoved.")
+ exit(False)
+
+
diff --git a/src/tests/regress/issue72.py b/src/tests/regress/issue72.py
new file mode 100755
index 0000000..d0c511b
--- /dev/null
+++ b/src/tests/regress/issue72.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+long_dir = 110*"a"
+long_b = 110*"b"
+long_filename = long_dir + "/"+ long_b
+long_filename2 = long_dir + "/" + 110*"c"
+
+os.mkdir(long_dir)
+open(long_filename, "w").close()
+os.symlink(long_b, long_filename2)
+a = opk.Opk(Package="a")
+a.write(data_files=[long_dir, long_filename, long_filename2])
+os.unlink(long_filename)
+os.unlink(long_filename2)
+os.rmdir(long_dir)
+opkgcl.install("a_1.0_all.opk")
+
+if not opkgcl.is_installed("a"):
+ print(__file__, ": Package 'a' not installed.")
+ exit(False)
+
+if not os.path.exists("{}/{}".format(cfg.offline_root, long_dir)):
+ print(__file__, ": dir with name longer than 100 "
+ "characters not created.")
+ exit(False)
+
+if not os.path.exists("{}/{}".format(cfg.offline_root, long_filename)):
+ print(__file__, ": file with a name longer than 100 characters, "
+ "in dir with name longer than 100 characters, "
+ "not created.")
+ exit(False)
+
+if not os.path.lexists("{}/{}".format(cfg.offline_root, long_filename2)):
+ print(__file__, ": symlink with a name longer than 100 characters, "
+ "pointing at a file with a name longer than "
+ "100 characters,"
+ "in dir with name longer than 100 characters, "
+ "not created.")
+ exit(False)
+
+linky = os.path.realpath("{}/{}".format(cfg.offline_root, long_filename2))
+linky_dst = "{}/{}".format(cfg.offline_root, long_filename)
+if linky != linky_dst:
+ print(__file__, ": symlink path truncated.")
+ exit(False)
+
+opkgcl.remove("a")
diff --git a/src/tests/regress/issue79.py b/src/tests/regress/issue79.py
new file mode 100755
index 0000000..30ba201
--- /dev/null
+++ b/src/tests/regress/issue79.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+
+import os
+import opk, cfg, opkgcl
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Version="1.0", Depends="b")
+o.add(Package="b", Version="1.0")
+o.add(Package="c", Version="1.0", Depends="b")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+opkgcl.install("a")
+opkgcl.install("c")
+
+opkgcl.flag_unpacked("a")
+
+o = opk.OpkGroup()
+o.add(Package="a", Version="1.0", Depends="b")
+o.add(Package="b", Version="1.0")
+o.add(Package="c", Version="2.0")
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+opkgcl.upgrade("--autoremove")
+
+if not opkgcl.is_installed("b", "1.0"):
+ print("b has been removed even though a still depends on it")
+ exit(False)
diff --git a/src/tests/regress/issue84.py b/src/tests/regress/issue84.py
new file mode 100755
index 0000000..1f5d43e
--- /dev/null
+++ b/src/tests/regress/issue84.py
@@ -0,0 +1,45 @@
+#!/usr/bin/python3
+
+import opk, cfg, opkgcl
+
+def cleanup():
+ opkgcl.remove("a1")
+ opkgcl.remove("b1")
+ opkgcl.remove("a")
+ opkgcl.remove("b")
+ opkgcl.remove('c')
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Provides="v", Depends="a1")
+o.add(Package="b", Provides="v", Depends="b1")
+o.add(Package="c", Depends="v")
+o.add(Package="a1")
+o.add(Package="b1")
+
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+# install ``a1`` directly
+opkgcl.install("a1_1.0_all.opk")
+if not opkgcl.is_installed("a1"):
+ print(__file__, ": package ``a1'' not installed.")
+ cleanup()
+ exit(False)
+
+# install ``c'' from repository
+opkgcl.install("c")
+if not opkgcl.is_installed("c"):
+ print(__file__, ": package ``c'' not installed.")
+ cleanup()
+ exit(False)
+
+if opkgcl.is_installed("b1"):
+ print(__file__, ": package ``b1'' is installed, but should not be.")
+ cleanup()
+ exit(False)
+
+cleanup()
diff --git a/src/tests/regress/issue85.py b/src/tests/regress/issue85.py
new file mode 100755
index 0000000..3250075
--- /dev/null
+++ b/src/tests/regress/issue85.py
@@ -0,0 +1,29 @@
+#!/usr/bin/python3
+
+import opk, cfg, opkgcl
+
+def cleanup():
+ opkgcl.remove("a")
+ opkgcl.remove("b")
+ opkgcl.remove('c')
+
+opk.regress_init()
+
+o = opk.OpkGroup()
+o.add(Package="a", Provides="v")
+o.add(Package="b", Provides="v", Depends="b_nonexistant")
+o.add(Package="c", Depends="v")
+
+o.write_opk()
+o.write_list()
+
+opkgcl.update()
+
+# install ``c'' from repository
+opkgcl.install("c")
+if not opkgcl.is_installed("c"):
+ print(__file__, ": package ``c'' not installed.")
+ cleanup()
+ exit(False)
+
+cleanup()
diff --git a/src/tests/regress/opk.py b/src/tests/regress/opk.py
new file mode 100644
index 0000000..f96037e
--- /dev/null
+++ b/src/tests/regress/opk.py
@@ -0,0 +1,111 @@
+import tarfile, os
+import cfg
+
+class Opk:
+ valid_control_fields = ["Package", "Version", "Depends", "Provides",\
+ "Replaces", "Conflicts", "Suggests", "Recommends",\
+ "Section", "Architecture", "Maintainer", "MD5Sum",\
+ "Size", "InstalledSize", "Filename", "Source",\
+ "Description", "OE", "Homepage", "Priority",\
+ "Conffiles"]
+
+ def __init__(self, **control):
+ for k in control.keys():
+ if k not in self.valid_control_fields:
+ raise Exception("Invalid control field: "
+ "{}".format(k))
+ if "Package" not in control.keys():
+ print("Cannot create opk without Package name.\n")
+ return None
+ if "Architecture" not in control.keys():
+ control["Architecture"] = "all"
+ if "Version" not in control.keys():
+ control["Version"] = "1.0"
+ self.control = control
+
+ def write(self, tar_not_ar=False, data_files=None):
+ filename = "{Package}_{Version}_{Architecture}.opk"\
+ .format(**self.control)
+ if os.path.exists(filename):
+ os.unlink(filename)
+ if os.path.exists("control"):
+ os.unlink("control")
+ if os.path.exists("control.tar.gz"):
+ os.unlink("control.tar.gz")
+ if os.path.exists("data.tar.gz"):
+ os.unlink("data.tar.gz")
+
+ f = open("control", "w")
+ for k in self.control.keys():
+ f.write("{}: {}\n".format(k, self.control[k]))
+ f.close()
+
+ tar = tarfile.open("control.tar.gz", "w:gz")
+ tar.add("control")
+ tar.close()
+
+ tar = tarfile.open("data.tar.gz", "w:gz")
+ if data_files:
+ for df in data_files:
+ tar.add(df)
+ tar.close()
+
+
+ if tar_not_ar:
+ tar = tarfile.open(filename, "w:gz")
+ tar.add("control.tar.gz")
+ tar.add("data.tar.gz")
+ tar.close()
+ else:
+ os.system("ar q {} control.tar.gz data.tar.gz \
+ 2>/dev/null".format(filename))
+
+ os.unlink("control")
+ os.unlink("control.tar.gz")
+ os.unlink("data.tar.gz")
+
+class OpkGroup:
+ def __init__(self):
+ self.opk_list = []
+
+ def add(self, **control):
+ self.opk_list.append(Opk(**control))
+
+ def addOpk(self, opk):
+ self.opk_list.append(opk)
+
+ def write_opk(self, tar_not_ar=False):
+ for o in self.opk_list:
+ o.write(tar_not_ar)
+
+ def write_list(self, filename="Packages"):
+ f = open(filename, "w")
+ for opk in self.opk_list:
+ for k in opk.control.keys():
+ f.write("{}: {}\n".format(k, opk.control[k]))
+ f.write("Filename: {Package}_{Version}_{Architecture}"
+ ".opk\n".format(**opk.control))
+ f.write("\n")
+ f.close()
+
+
+def regress_init():
+ """
+ Initialisation and sanity checking.
+ """
+
+ if not os.access(cfg.opkgcl, os.X_OK):
+ print("Cannot exec {}".format(cfg.opkgcl))
+ exit(False)
+
+ os.chdir(cfg.opkdir)
+
+ os.system("rm -fr {}".format(cfg.offline_root))
+
+ os.makedirs("{}/usr/lib/opkg".format(cfg.offline_root))
+ os.makedirs("{}/etc/opkg".format(cfg.offline_root))
+
+ f = open("{}/etc/opkg/opkg.conf".format(cfg.offline_root), "w")
+ f.write("arch all 1\n")
+ f.write("src test file:{}\n".format(cfg.opkdir))
+ f.close()
diff --git a/src/tests/regress/opkgcl.py b/src/tests/regress/opkgcl.py
new file mode 100755
index 0000000..47e7dd3
--- /dev/null
+++ b/src/tests/regress/opkgcl.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python3
+
+import os, subprocess
+import cfg
+
+def opkgcl(opkg_args):
+ cmd = "{} -o {} {}".format(cfg.opkgcl, cfg.offline_root, opkg_args)
+ #print(cmd)
+ return subprocess.getstatusoutput(cmd)
+
+def install(pkg_name, flags=""):
+ return opkgcl("{} install {}".format(flags, pkg_name))[0]
+
+def remove(pkg_name, flags=""):
+ return opkgcl("{} remove {}".format(flags, pkg_name))[0]
+
+def update():
+ return opkgcl("update")[0]
+
+def upgrade(params=None):
+ if params:
+ opkgcl("upgrade {}".format(params))[0]
+ else:
+ return opkgcl("upgrade")[0]
+
+def files(pkg_name):
+ output = opkgcl("files {}".format(pkg_name))[1]
+ return output.split("\n")[1:]
+
+
+def flag_unpacked(pkg_name):
+ out = opkgcl("flag unpacked {}".format(pkg_name))
+ return out == "Setting flags for package {} to unpacked.".format(pkg_name)
+
+def is_installed(pkg_name, version=None):
+ out = opkgcl("list_installed {}".format(pkg_name))[1]
+ if len(out) == 0 or out.split()[0] != pkg_name:
+ return False
+ if version and out.split()[2] != version:
+ return False
+ if not os.path.exists("{}/usr/lib/opkg/info/{}.control"\
+ .format(cfg.offline_root, pkg_name)):
+ return False
+ return True
+
+def is_autoinstalled(pkg_name):
+ status_path = "{}/usr/lib/opkg/status".format(cfg.offline_root)
+ if not os.path.exists(status_path):
+ return False
+ status_file = open(status_path, "r")
+ status = status_file.read()
+ status_file.close()
+ index_start = status.find("Package: {}".format(pkg_name))
+ if index_start < 0:
+ return False
+ index_end = status.find("\n\n", index_start)
+ return status.find("Auto-Installed: yes", index_start, index_end) >= 0
+
+
+if __name__ == '__main__':
+ import sys
+ (status, output) = opkgcl(" ".join(sys.argv[1:]))
+ print(output)
+ exit(status)
diff --git a/src/tests/regress/update_loses_autoinstalled_flag.py b/src/tests/regress/update_loses_autoinstalled_flag.py
new file mode 100644
index 0000000..5ae030c
--- /dev/null
+++ b/src/tests/regress/update_loses_autoinstalled_flag.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python3
+
+import os
+import opk, cfg, opkgcl
+
+bug = True
+
+opk.regress_init()
+
+open("asdf", "w").close()
+a = opk.Opk(Package="a", Version="1.0", Depends="b")
+a.write()
+b = opk.Opk(Package="b", Version="1.0")
+b.write(data_files=["asdf"])
+
+o = opk.OpkGroup()
+o.addOpk(a)
+o.addOpk(b)
+o.write_list()
+
+opkgcl.update()
+opkgcl.install("a")
+
+if not opkgcl.is_autoinstalled("b"):
+ print("b is not autoinstalled")
+ exit(False)
+
+if (bug):
+ a = opk.Opk(Package="a", Version="2.0", Depends="b")
+ a.write()
+ b = opk.Opk(Package="b", Version="2.0")
+ b.write(data_files=["asdf"])
+
+ o = opk.OpkGroup()
+ o.addOpk(a)
+ o.addOpk(b)
+ o.write_list()
+
+ opkgcl.update()
+ opkgcl.upgrade();
+
+ if not opkgcl.is_autoinstalled("b"):
+ print("b is not autoinstalled anymore")
+ exit(False)
+
+a = opk.Opk(Package="a", Version="3.0")
+a.write(data_files=["asdf"])
+os.unlink("asdf")
+
+o = opk.OpkGroup()
+o.addOpk(a)
+o.write_list()
+
+opkgcl.update()
+opkgcl.upgrade();
+
+if opkgcl.is_installed("b", "2.0"):
+ print("b is still installed")
+ exit(False)
+
+if not opkgcl.is_installed("a", "3.0"):
+ print("a is not installed")
+ exit(False)
diff --git a/src/utils/.svn/all-wcprops b/src/utils/.svn/all-wcprops
new file mode 100644
index 0000000..911d4f7
--- /dev/null
+++ b/src/utils/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 29
+/svn/!svn/ver/439/trunk/utils
+END
+update-alternatives.in
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svn/!svn/ver/439/trunk/utils/update-alternatives.in
+END
+opkg-key
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svn/!svn/ver/106/trunk/utils/opkg-key
+END
+Makefile.am
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/402/trunk/utils/Makefile.am
+END
diff --git a/src/utils/.svn/entries b/src/utils/.svn/entries
new file mode 100644
index 0000000..9ecb81a
--- /dev/null
+++ b/src/utils/.svn/entries
@@ -0,0 +1,130 @@
+10
+
+dir
+635
+http://opkg.googlecode.com/svn/trunk/utils
+http://opkg.googlecode.com/svn
+
+
+
+2009-12-03T04:11:26.978382Z
+439
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+e8e0d7a0-c8d9-11dd-a880-a1081c7ac358
+
+update-alternatives.in
+file
+
+
+
+
+2012-02-03T08:11:57.175042Z
+073ea7a18d937045725fc9951b5dc8ec
+2009-12-03T04:11:26.978382Z
+439
+graham.gower
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4528
+
+opkg-key
+file
+
+
+
+
+2012-02-03T08:11:57.175042Z
+18f0724827a722399bedc053eb8ceb7c
+2008-12-15T05:16:36.570675Z
+106
+ticktock35
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1671
+
+Makefile.am
+file
+
+
+
+
+2012-02-03T08:11:57.175042Z
+aaace2c1890cfc1f041502207fe30261
+2009-11-27T12:27:33.204296Z
+402
+florian.boor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+72
+
diff --git a/src/utils/.svn/prop-base/opkg-key.svn-base b/src/utils/.svn/prop-base/opkg-key.svn-base
new file mode 100644
index 0000000..869ac71
--- /dev/null
+++ b/src/utils/.svn/prop-base/opkg-key.svn-base
@@ -0,0 +1,5 @@
+K 14
+svn:executable
+V 1
+*
+END
diff --git a/src/utils/.svn/text-base/Makefile.am.svn-base b/src/utils/.svn/text-base/Makefile.am.svn-base
new file mode 100644
index 0000000..acac628
--- /dev/null
+++ b/src/utils/.svn/text-base/Makefile.am.svn-base
@@ -0,0 +1,3 @@
+bin_SCRIPTS = update-alternatives opkg-key
+
+EXTRA_DIST = $(bin_SCRIPTS)
diff --git a/src/utils/.svn/text-base/opkg-key.svn-base b/src/utils/.svn/text-base/opkg-key.svn-base
new file mode 100644
index 0000000..266bb66
--- /dev/null
+++ b/src/utils/.svn/text-base/opkg-key.svn-base
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+# Based on apt-key from apt-0.6.25
+# Licensed under GPL Version 2
+
+set -e
+
+usage() {
+ echo "Usage: opkg-key [options] command [arguments]"
+ echo
+ echo "Manage opkg's list of trusted keys"
+ echo
+ echo " opkg-key add <file> - add the key contained in <file> ('-' for stdin)"
+ echo " opkg-key del <keyid> - remove the key <keyid>"
+ echo " opkg-key list - list keys"
+ echo
+ echo "Options:"
+ echo " -o <root> Use <root> as the offline root directory"
+ echo
+}
+
+if [ "$1" = "-o" ]; then
+ ROOT=$2
+ shift 2
+ echo "Note: using \"$ROOT\" as root path"
+else
+ ROOT=""
+fi
+
+command="$1"
+if [ -z "$command" ]; then
+ usage
+ exit 1
+fi
+shift
+
+if [ "$command" != "help" ] && ! which gpg >/dev/null 2>&1; then
+ echo >&2 "Warning: gnupg does not seem to be installed."
+ echo >&2 "Warning: opkg-key requires gnupg for most operations."
+ echo >&2
+fi
+
+# We don't use a secret keyring, of course, but gpg panics and
+# implodes if there isn't one available
+
+GPG="gpg --no-options --no-default-keyring --keyring $ROOT/etc/opkg/trusted.gpg --secret-keyring $ROOT/etc/opkg/secring.gpg --trustdb-name $ROOT/etc/opkg/trustdb.gpg"
+
+case "$command" in
+ add)
+ $GPG --quiet --batch --import "$1"
+ echo "OK"
+ ;;
+ del|rm|remove)
+ $GPG --quiet --batch --delete-key --yes "$1"
+ echo "OK"
+ ;;
+ list)
+ $GPG --batch --list-keys
+ ;;
+ finger*)
+ $GPG --batch --fingerprint
+ ;;
+ adv*)
+ echo "Executing: $GPG $*"
+ $GPG $*
+ ;;
+ help)
+ usage
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+esac
diff --git a/src/utils/.svn/text-base/update-alternatives.in.svn-base b/src/utils/.svn/text-base/update-alternatives.in.svn-base
new file mode 100644
index 0000000..34d89f1
--- /dev/null
+++ b/src/utils/.svn/text-base/update-alternatives.in.svn-base
@@ -0,0 +1,197 @@
+#!/bin/sh
+# update-alternatives
+#
+# Copyright (C) 2001 Carl D. Worth
+#
+# This program was inspired by the Debian update-alternatives program
+# which is Copyright (C) 1995 Ian Jackson. This version of
+# update-alternatives is command-line compatible with Debian's for a
+# subset of the options, (only --install, --remove, and --help)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+set -e
+
+# admin dir
+ad="$OPKG_OFFLINE_ROOT@opkglibdir@/opkg/alternatives"
+
+usage() {
+ echo "update-alternatives: $*
+
+Usage: update-alternatives --install <link> <name> <path> <priority>
+ update-alternatives --remove <name> <path>
+ update-alternatives --help
+<link> is the link pointing to the provided path (ie. /usr/bin/foo).
+<name> is the name in $ad/alternatives (ie. foo)
+<path> is the name referred to (ie. /usr/bin/foo-extra-spiffy)
+<priority> is an integer; options with higher numbers are chosen.
+" >&2
+ exit 2
+}
+
+quit() {
+ echo "update-alternatives: $*" >&2
+ exit 2
+}
+
+register_alt() {
+ [ $# -lt 2 ] && return 1
+ local name="$1"
+ local link="$2"
+
+ if [ ! -d $ad ]; then
+ mkdir -p $ad
+ fi
+
+ if [ -e "$ad/$name" ]; then
+ local olink=`head -n 1 $ad/$name`
+ if [ "$link" != "$olink" ]; then
+ echo "update-alternatives: Error: cannot register alternative $name to $link since it is already registered to $olink" >&2
+ return 1
+ fi
+ else
+ echo "$link" > "$ad/$name"
+ fi
+
+ return 0
+}
+
+protect_slashes() {
+ sed -e 's/\//\\\//g'
+}
+
+remove_alt() {
+ [ $# -lt 2 ] && return 1
+ local name="$1"
+ local path="$2"
+
+ [ ! -f $ad/$name ] && return 0
+
+ path=`echo $path | protect_slashes`
+ sed -ne "/^$path\>.*/!p" $ad/$name > $ad/$name.new
+ mv $ad/$name.new $ad/$name
+}
+
+add_alt() {
+ [ $# -lt 3 ] && return 1
+ local name="$1"
+ local path="$2"
+ local priority="$3"
+ remove_alt $name $path
+ echo "$path $priority" >> $ad/$name
+}
+
+find_best_alt() {
+ [ $# -lt 1 ] && return 1
+ [ ! -f $ad/$name ] && return 0
+
+ link=$OPKG_OFFLINE_ROOT/`head -n 1 $ad/$name`
+
+ prio=`sed -ne "1!p" $ad/$name | sed -e "s/\(.*\) \(.*\)/\2 \1/g" | sort -nr | head -n 1 | sed 's/ [^ ]*$//'`
+ if [ -z "$prio" ]; then
+ echo "update-alternatives: removing $link as no more alternatives exist for it"
+ rm $ad/$name
+ if [ -L $link ]; then
+ rm $link
+ fi
+ return 0
+ fi
+
+ ## Find last line with highest priority.
+ path=`grep "${prio}$" $ad/$name | tail -n 1 | sed 's/ [^ ]*$//'`
+
+ if [ ! -e $link -o -L $link ]; then
+ local link_dir=`dirname $link`
+ if [ ! -d $link_dir ]; then
+ mkdir -p $link_dir
+ fi
+ if [ -h $link -a -d $link ]; then
+ # If $link exists and the target is a directory,
+ # 'ln -sf $path $link' doesn't replace the link to
+ # that directory, it creates new link inside.
+ echo "update-alternatives: Removing $link".
+ rm -f $link
+ fi
+ ln -sf $path $link
+ echo "update-alternatives: Linking $link to $path"
+ else
+ echo "update-alternatives: Error: not linking $link to $path since $link exists and is not a link"
+ return 1
+ fi
+
+ return 0
+}
+
+do_install() {
+ if [ $# -lt 4 ]; then
+ usage "--install needs <link> <name> <path> <priority>"
+ fi
+ local link="$1"
+ local name="$2"
+ local path="$3"
+ local priority="$4"
+
+ path=`echo $path | sed 's|/\+|/|g'`
+
+ # This is a bad hack, but I haven't thought of a cleaner solution yet...
+ [ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"`
+
+ register_alt $name $link
+ add_alt $name $path $priority
+ find_best_alt $name
+}
+
+do_remove() {
+ if [ $# -lt 2 ]; then
+ usage "--remove needs <name> <path>"
+ fi
+ local name="$1"
+ local path="$2"
+
+ path=`echo $path | sed 's|/\+|/|g'`
+
+ # This is a bad hack, but I haven't thought of a cleaner solution yet...
+ [ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"`
+
+ remove_alt $name $path
+ find_best_alt $name
+}
+
+###
+# update-alternatives "main"
+###
+
+while [ $# -gt 0 ]; do
+ arg="$1"
+ shift
+
+ case $arg in
+ --help)
+ usage "help:"
+ exit 0
+ ;;
+ --install)
+ do_install $*
+ exit $?
+ ;;
+ --remove)
+ do_remove $*
+ exit $?
+ ;;
+ *)
+ usage "unknown argument \`$arg'"
+ ;;
+ esac
+done
+
+usage "at least one of --install or --remove must appear"
+
+exit 0
diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
new file mode 100644
index 0000000..acac628
--- /dev/null
+++ b/src/utils/Makefile.am
@@ -0,0 +1,3 @@
+bin_SCRIPTS = update-alternatives opkg-key
+
+EXTRA_DIST = $(bin_SCRIPTS)
diff --git a/src/utils/opkg-key b/src/utils/opkg-key
new file mode 100755
index 0000000..266bb66
--- /dev/null
+++ b/src/utils/opkg-key
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+# Based on apt-key from apt-0.6.25
+# Licensed under GPL Version 2
+
+set -e
+
+usage() {
+ echo "Usage: opkg-key [options] command [arguments]"
+ echo
+ echo "Manage opkg's list of trusted keys"
+ echo
+ echo " opkg-key add <file> - add the key contained in <file> ('-' for stdin)"
+ echo " opkg-key del <keyid> - remove the key <keyid>"
+ echo " opkg-key list - list keys"
+ echo
+ echo "Options:"
+ echo " -o <root> Use <root> as the offline root directory"
+ echo
+}
+
+if [ "$1" = "-o" ]; then
+ ROOT=$2
+ shift 2
+ echo "Note: using \"$ROOT\" as root path"
+else
+ ROOT=""
+fi
+
+command="$1"
+if [ -z "$command" ]; then
+ usage
+ exit 1
+fi
+shift
+
+if [ "$command" != "help" ] && ! which gpg >/dev/null 2>&1; then
+ echo >&2 "Warning: gnupg does not seem to be installed."
+ echo >&2 "Warning: opkg-key requires gnupg for most operations."
+ echo >&2
+fi
+
+# We don't use a secret keyring, of course, but gpg panics and
+# implodes if there isn't one available
+
+GPG="gpg --no-options --no-default-keyring --keyring $ROOT/etc/opkg/trusted.gpg --secret-keyring $ROOT/etc/opkg/secring.gpg --trustdb-name $ROOT/etc/opkg/trustdb.gpg"
+
+case "$command" in
+ add)
+ $GPG --quiet --batch --import "$1"
+ echo "OK"
+ ;;
+ del|rm|remove)
+ $GPG --quiet --batch --delete-key --yes "$1"
+ echo "OK"
+ ;;
+ list)
+ $GPG --batch --list-keys
+ ;;
+ finger*)
+ $GPG --batch --fingerprint
+ ;;
+ adv*)
+ echo "Executing: $GPG $*"
+ $GPG $*
+ ;;
+ help)
+ usage
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+esac
diff --git a/src/utils/update-alternatives.in b/src/utils/update-alternatives.in
new file mode 100644
index 0000000..34d89f1
--- /dev/null
+++ b/src/utils/update-alternatives.in
@@ -0,0 +1,197 @@
+#!/bin/sh
+# update-alternatives
+#
+# Copyright (C) 2001 Carl D. Worth
+#
+# This program was inspired by the Debian update-alternatives program
+# which is Copyright (C) 1995 Ian Jackson. This version of
+# update-alternatives is command-line compatible with Debian's for a
+# subset of the options, (only --install, --remove, and --help)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+set -e
+
+# admin dir
+ad="$OPKG_OFFLINE_ROOT@opkglibdir@/opkg/alternatives"
+
+usage() {
+ echo "update-alternatives: $*
+
+Usage: update-alternatives --install <link> <name> <path> <priority>
+ update-alternatives --remove <name> <path>
+ update-alternatives --help
+<link> is the link pointing to the provided path (ie. /usr/bin/foo).
+<name> is the name in $ad/alternatives (ie. foo)
+<path> is the name referred to (ie. /usr/bin/foo-extra-spiffy)
+<priority> is an integer; options with higher numbers are chosen.
+" >&2
+ exit 2
+}
+
+quit() {
+ echo "update-alternatives: $*" >&2
+ exit 2
+}
+
+register_alt() {
+ [ $# -lt 2 ] && return 1
+ local name="$1"
+ local link="$2"
+
+ if [ ! -d $ad ]; then
+ mkdir -p $ad
+ fi
+
+ if [ -e "$ad/$name" ]; then
+ local olink=`head -n 1 $ad/$name`
+ if [ "$link" != "$olink" ]; then
+ echo "update-alternatives: Error: cannot register alternative $name to $link since it is already registered to $olink" >&2
+ return 1
+ fi
+ else
+ echo "$link" > "$ad/$name"
+ fi
+
+ return 0
+}
+
+protect_slashes() {
+ sed -e 's/\//\\\//g'
+}
+
+remove_alt() {
+ [ $# -lt 2 ] && return 1
+ local name="$1"
+ local path="$2"
+
+ [ ! -f $ad/$name ] && return 0
+
+ path=`echo $path | protect_slashes`
+ sed -ne "/^$path\>.*/!p" $ad/$name > $ad/$name.new
+ mv $ad/$name.new $ad/$name
+}
+
+add_alt() {
+ [ $# -lt 3 ] && return 1
+ local name="$1"
+ local path="$2"
+ local priority="$3"
+ remove_alt $name $path
+ echo "$path $priority" >> $ad/$name
+}
+
+find_best_alt() {
+ [ $# -lt 1 ] && return 1
+ [ ! -f $ad/$name ] && return 0
+
+ link=$OPKG_OFFLINE_ROOT/`head -n 1 $ad/$name`
+
+ prio=`sed -ne "1!p" $ad/$name | sed -e "s/\(.*\) \(.*\)/\2 \1/g" | sort -nr | head -n 1 | sed 's/ [^ ]*$//'`
+ if [ -z "$prio" ]; then
+ echo "update-alternatives: removing $link as no more alternatives exist for it"
+ rm $ad/$name
+ if [ -L $link ]; then
+ rm $link
+ fi
+ return 0
+ fi
+
+ ## Find last line with highest priority.
+ path=`grep "${prio}$" $ad/$name | tail -n 1 | sed 's/ [^ ]*$//'`
+
+ if [ ! -e $link -o -L $link ]; then
+ local link_dir=`dirname $link`
+ if [ ! -d $link_dir ]; then
+ mkdir -p $link_dir
+ fi
+ if [ -h $link -a -d $link ]; then
+ # If $link exists and the target is a directory,
+ # 'ln -sf $path $link' doesn't replace the link to
+ # that directory, it creates new link inside.
+ echo "update-alternatives: Removing $link".
+ rm -f $link
+ fi
+ ln -sf $path $link
+ echo "update-alternatives: Linking $link to $path"
+ else
+ echo "update-alternatives: Error: not linking $link to $path since $link exists and is not a link"
+ return 1
+ fi
+
+ return 0
+}
+
+do_install() {
+ if [ $# -lt 4 ]; then
+ usage "--install needs <link> <name> <path> <priority>"
+ fi
+ local link="$1"
+ local name="$2"
+ local path="$3"
+ local priority="$4"
+
+ path=`echo $path | sed 's|/\+|/|g'`
+
+ # This is a bad hack, but I haven't thought of a cleaner solution yet...
+ [ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"`
+
+ register_alt $name $link
+ add_alt $name $path $priority
+ find_best_alt $name
+}
+
+do_remove() {
+ if [ $# -lt 2 ]; then
+ usage "--remove needs <name> <path>"
+ fi
+ local name="$1"
+ local path="$2"
+
+ path=`echo $path | sed 's|/\+|/|g'`
+
+ # This is a bad hack, but I haven't thought of a cleaner solution yet...
+ [ -n "$OPKG_OFFLINE_ROOT" ] && path=`echo $path | sed "s|^$OPKG_OFFLINE_ROOT/*|/|"`
+
+ remove_alt $name $path
+ find_best_alt $name
+}
+
+###
+# update-alternatives "main"
+###
+
+while [ $# -gt 0 ]; do
+ arg="$1"
+ shift
+
+ case $arg in
+ --help)
+ usage "help:"
+ exit 0
+ ;;
+ --install)
+ do_install $*
+ exit $?
+ ;;
+ --remove)
+ do_remove $*
+ exit $?
+ ;;
+ *)
+ usage "unknown argument \`$arg'"
+ ;;
+ esac
+done
+
+usage "at least one of --install or --remove must appear"
+
+exit 0