scummvm random work
[patches.git] / emerge-svn.diff
CommitLineData
5e993f12 1diff -Nru --exclude=CVS --exclude=env.sh busybox-1.00/archival/Config.in busybox/archival/Config.in
2--- busybox-1.00/archival/Config.in 2004-03-15 09:28:16.000000000 +0100
3+++ busybox/archival/Config.in 2005-03-29 13:45:03.000000000 +0200
4@@ -97,6 +97,14 @@
5 However it saves space as none of the extra dpkg-deb, ar or tar options are
6 needed, they are linked to internally.
7
8+config CONFIG_EMERGE
9+ bool "emerge workalike for gentoo packages"
10+ default n
11+ depends on CONFIG_WGET && CONFIG_TBZ2PKG
12+ help
13+ This allows busybox to fetch and install binary packages
14+ from the gentoo portage system.
15+
16 config CONFIG_GUNZIP
17 bool "gunzip"
18 default n
19@@ -205,6 +213,13 @@
20 help
21 Enable use of long options, increases size by about 400 Bytes
22
23+config CONFIG_TBZ2PKG
24+ bool "tbz2pkg"
25+ default n
26+ depends on CONFIG_FEATURE_TAR_BZIP2
27+ help
28+ Install and uninstall gentoo binary packages
29+
30 config CONFIG_UNCOMPRESS
31 bool "uncompress"
32 default n
33diff -Nru --exclude=CVS --exclude=env.sh busybox-1.00/archival/Makefile.in busybox/archival/Makefile.in
34--- busybox-1.00/archival/Makefile.in 2004-10-08 09:45:09.000000000 +0200
35+++ busybox/archival/Makefile.in 2005-04-02 18:02:27.000000000 +0200
36@@ -30,11 +30,13 @@
37 ARCHIVAL-$(CONFIG_CPIO) += cpio.o
38 ARCHIVAL-$(CONFIG_DPKG) += dpkg.o
39 ARCHIVAL-$(CONFIG_DPKG_DEB) += dpkg_deb.o
40+ARCHIVAL-$(CONFIG_EMERGE) += emerge.o gentoo_shared.o
41 ARCHIVAL-$(CONFIG_GUNZIP) += gunzip.o
42 ARCHIVAL-$(CONFIG_GZIP) += gzip.o
43 ARCHIVAL-$(CONFIG_RPM2CPIO) += rpm2cpio.o
44 ARCHIVAL-$(CONFIG_RPM) += rpm.o
45 ARCHIVAL-$(CONFIG_TAR) += tar.o
46+ARCHIVAL-$(CONFIG_TBZ2PKG) += tbz2pkg.o gentoo_shared.o
47 ARCHIVAL-$(CONFIG_UNCOMPRESS) += uncompress.o
48 ARCHIVAL-$(CONFIG_UNZIP) += unzip.o
49
50diff -Nru --exclude=CVS --exclude=env.sh busybox-1.00/archival/emerge.c busybox/archival/emerge.c
51--- busybox-1.00/archival/emerge.c 1970-01-01 01:00:00.000000000 +0100
52+++ busybox/archival/emerge.c 2005-06-08 20:17:34.000000000 +0200
53@@ -0,0 +1,768 @@
54+/*
55+* Distributed under the terms of the GNU General Public License v2
56+* $Header: /home/collar_b/programs/cvs/busybox/archival/emerge.c,v 1.27 2005/06/08 18:17:34 collar_b Exp $
57+*
58+* emerge: a gentoo-emerge workalike for embedded systems, integrated
59+* into the busybox suite
60+*
61+* Written by Benjamin Collar
62+* Copyright (C) 2005, Benjamin Collar
63+*
64+********************************************************************
65+* This program is free software; you can redistribute it and/or
66+* modify it under the terms of the GNU General Public License as
67+* published by the Free Software Foundation; either version 2 of the
68+* License, or (at your option) any later version.
69+*
70+* This program is distributed in the hope that it will be useful, but
71+* WITHOUT ANY WARRANTY; without even the implied warranty of
72+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
73+* General Public License for more details.
74+*
75+* You should have received a copy of the GNU General Public License
76+* along with this program; if not, write to the Free Software
77+* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
78+* MA 02111-1307, USA.
79+*/
80+
81+/* note about source code organization */
82+/* this file is organized like this:
83+ * structs & other declarations
84+ * generally useful stuff
85+ * functions that start with do_ relate directly to an "action", ie a command
86+ * helper functions for the do_ start with the <command>_
87+ * functions that start with parse_ are used for processing the index file
88+ * other things should hopefully be clear :)
89+ */
90+
91+#include "busybox.h"
92+#include <stdlib.h>
93+#include <fcntl.h>
94+#include <unistd.h>
95+#include <dirent.h>
96+#include <sys/types.h>
97+#include <sys/stat.h>
98+#include <sys/wait.h>
99+#include <assert.h>
100+#include <getopt.h>
101+#include <errno.h>
102+#include <ctype.h>
103+#include "tbz2pkg.h"
104+
105+#define file_exists(f) (access(f, R_OK) == 0)
106+#define dir_exists(f) (access(f, R_OK) == 0)
107+
108+
109+typedef struct pkg_info_s {
110+ llist_t *packages;
111+ package_t** searchable_packages; /* sorted pointers to package names; use bsearch to find them */
112+ int num_packages; /* length of searchable_packages array */
113+} pkg_info_t;
114+
115+extern int wget_main(int argc, char **argv);
116+configurables_t conf;
117+int (*action) (const package_t*);/* this is the action we'll take, after handling cmdline, etc */
118+static pkg_info_t pkg_info;
119+
120+/* some useful functions */
121+static int
122+mkalldirs(char *dir)
123+{
124+ return bb_make_directory(dir, -1, FILEUTILS_RECUR);
125+}
126+
127+static package_t*
128+find_in_index (package_t* pkg)
129+{
130+ void* result;
131+ result = bsearch((void*) pkg, (const void*) pkg_info.searchable_packages,
132+ pkg_info.num_packages, sizeof(package_t*), bfind_compare);
133+ if (result) {
134+ return (*(package_t**)result);
135+ }
136+ return 0;
137+}
138+
139+static int
140+fetch_package(package_t* package)
141+{
142+ /* using the package in package-name (which is category/package), figure
143+ * out the actual package name and URL. Then fetch it. return 0 when it works.
144+ */
145+ /* append the category/package to the binhost to create the url */
146+
147+ static char fullurl[GEM_PATH_MAX];
148+ static char target[GEM_PATH_MAX];
149+ static char pkgver[GEM_NAME_LEN*2+2];
150+ sprintf(pkgver, "%s-%s.tbz2", package->name, package->version);
151+ if (!conf.pretend) {
152+ sprintf(msg, "Fetching package %s/%s", package->category, pkgver);
153+ einfo(msg);
154+ } else {
155+ sprintf(msg, "Would fetch %s/%s", package->category, pkgver);
156+ einfo(msg);
157+ return 0;
158+ }
159+ sprintf(target, "%s/All/", conf.pkgdir);
160+ /* make sure the package download directory exists */
161+ if ( mkalldirs(target) != 0 )
162+ edie("Failed to create package download directory");
163+ /* check if package already exists; if so, return ok */
164+ strcat(target, pkgver);
165+ if ( file_exists(target) ) {
166+ sprintf(msg, "Package already fetched: %s", target);
167+ einfo(msg);
168+ /* further processing expects msg to contain path to downloaded file */
169+ /* REFACTOR THIS */
170+ strcpy(msg, target);
171+ return 0;
172+ }
173+ sprintf(target, "%s/All/", conf.pkgdir);
174+ /* is it correct that the package file will be in http://binhost/category/abc-1.2.3.tbz2 ? */
175+ sprintf(fullurl, "%s/%s/%s", conf.binhost, package->category, pkgver);
176+ {
177+ char *cmdline[] = { "wget", "-c", "-P", target, fullurl, 0 };
178+ pid_t child=fork();
179+ if ( child == 0 ) {
180+ execvp("/proc/self/exe", cmdline);
181+ } else {
182+ int status, wgrval;
183+ wait(&status);
184+ if (WIFEXITED(status)) {
185+ wgrval = WEXITSTATUS(status);
186+ if (wgrval != 0) {
187+ edie("Failed to fetch package");
188+ } else {
189+ strcat(target, pkgver);
190+ sprintf(msg, "Package saved to %s", target);
191+ einfo(msg);
192+ }
193+ sprintf(msg, "%s/%s/%s", conf.pkgdir, package->category, pkgver);
194+ if (symlink(target, msg) != 0 && errno != EEXIST) {
195+ edie("Failed to symlink package into correct subdirectory");
196+ }
197+ /* save targetdir into msg; another function will use it */
198+ strcpy(msg, target);
199+ return 0;
200+ }
201+ }
202+ }
203+ return 1;
204+}
205+
206+static int
207+do_fetch(const package_t * user_pkg)
208+{
209+ llist_t* list;
210+ package_t *dep_pkg, *index_pkg;
211+ int rval=0;
212+ index_pkg = user_pkg->index_pkg;
213+ if (!index_pkg) {
214+ eerror("Package not found in index, cannot fetch!");
215+ return 1;
216+ }
217+ list = index_pkg->depends;
218+ while (list) {
219+ dep_pkg = decode_namespec((char*) list->data);
220+ dep_pkg->index_pkg = find_in_index(dep_pkg);
221+ if (!dep_pkg->index_pkg) {
222+ sprintf(msg, "Dependency %s for %s not found in index",
223+ dep_pkg->name, user_pkg->name);
224+ eerror(msg);
225+ rval = 1;
226+ } else {
227+ rval = rval ? rval : do_fetch(dep_pkg);
228+ }
229+ free(dep_pkg);
230+ list = list->link;
231+ }
232+ if (conf.pretend) {
233+ sprintf(msg, "Would fetch package %s\n", user_pkg->name);
234+ einfo(msg);
235+ return 0;
236+ }
237+ return rval ? rval : fetch_package(index_pkg);
238+}
239+
240+static void
241+do_info(void)
242+{
243+ bb_printf("PKGDIR=%s\n", (conf.pkgdir == NULL) ? "" : conf.pkgdir);
244+ bb_printf("PKG_DBDIR=%s\n", (conf.pkg_dbdir == NULL) ? "" : conf.pkg_dbdir);
245+ bb_printf("PORTAGE_BINHOST=%s\n",
246+ (conf.binhost == NULL) ? "" : conf.binhost);
247+ bb_printf("PORTAGE_TMPDIR=%s\n",
248+ (conf.tmpdir == NULL) ? "" : conf.tmpdir);
249+ bb_printf("ROOT=%s\n", (conf.root == NULL) ? "" : conf.root);
250+ bb_printf("INDEX_FILE=%s\n", (conf.index == NULL) ? "" : conf.index);
251+}
252+
253+static int do_merge(const package_t* p);
254+
255+static int
256+merge_should_install(package_t* p)
257+{
258+ static package_t tmppkg;
259+ int rval=0;
260+ llist_t *installed, *t;
261+ memcpy(&tmppkg, p, sizeof(package_t));
262+ tmppkg.modifier[0]='>';
263+ tmppkg.modifier[1]='=';
264+ installed = find_package_on_disk(&tmppkg);
265+ rval = installed == 0;
266+ while (installed) {
267+ t = installed->link;
268+ free(installed);
269+ installed = t;
270+ }
271+ return rval;
272+}
273+
274+static int
275+merge_deps(package_t* p)
276+{
277+ llist_t* list = p->depends;
278+ package_t* dep_pkg=0;
279+ int rval = 0;
280+ sprintf(msg, "Merging dependencies of %s", p->name);
281+ einfo(msg);
282+ if (conf.debug) { print_pkg(p); }
283+ while (list) {
284+ dep_pkg = decode_namespec((char*) list->data);
285+ if (strcmp(dep_pkg->category, "virtual") == 0) {
286+ rval = rval ? 1 : 0;
287+ sprintf(msg, "Can't do virtual dependencies yet. Please make sure %s/%s is installed",
288+ dep_pkg->category, dep_pkg->name);
289+ eerror(msg);
290+ } else {
291+ dep_pkg->index_pkg = find_in_index(dep_pkg);
292+ if (!dep_pkg->index_pkg) {
293+ rval = 1;
294+ } else {
295+ rval = rval ? 1 : do_merge(dep_pkg);
296+ }
297+ }
298+ free(dep_pkg);
299+ list = list->link;
300+ }
301+ einfo("Done merging dependencies");
302+ return rval;
303+}
304+
305+static int
306+do_merge(const package_t* user_pkg)
307+{
308+ package_t* index_pkg = user_pkg->index_pkg;
309+ sprintf(msg, "Merging package %s", user_pkg->name);
310+ einfo(msg);
311+ if (!index_pkg) {
312+ eerror("Package not found in index");
313+ return 1;
314+ }
315+ if (!merge_should_install(index_pkg)) {
316+ sprintf(msg, "Package %s already up-to-date", user_pkg->name);
317+ einfo(msg);
318+ return 0;
319+ }
320+ if (merge_deps(index_pkg) != 0) { eerror("Failed to merge dependencies"); return 1; }
321+ if (fetch_package(index_pkg) != 0) { eerror("Failed to fetch package"); return 1; }
322+
323+ /* fetch puts the filename into msg, so give that to tbz2 */
324+ if (conf.pretend) {
325+ sprintf(msg, "Would merge %s", user_pkg->name);
326+ einfo(msg);
327+ return 0;
328+ }
329+ if (tbz2_install_file(msg, &conf) <= 0) { eerror("Failed to install package"); return 1; }
330+ sprintf(msg, "Package %s merged successfully", user_pkg->name);
331+ einfo(msg);
332+ return 0;
333+}
334+
335+static int
336+do_unmerge(const package_t* user_pkg)
337+{
338+ package_t* index_pkg = user_pkg->index_pkg, *installed_pkg=0;
339+ int rval=0, should_free=0;
340+ llist_t* installed_pkgs, *l;
341+ if (!index_pkg) {
342+ index_pkg = xmalloc(sizeof(package_t));
343+ memcpy(index_pkg, user_pkg, sizeof(package_t));
344+ sprintf(msg, "Unable to find package %s in index, continuing...", user_pkg->name);
345+ should_free=1;
346+ }
347+ if (conf.pretend) {
348+ sprintf(msg, "Would unmerge %s", user_pkg->name);
349+ einfo(msg);
350+ rval = 0;
351+ }
352+ installed_pkgs = find_package_on_disk(index_pkg);
353+ if (!installed_pkgs) {
354+ einfo("Nothing to unmerge");
355+ }
356+ while (installed_pkgs) {
357+ installed_pkg = (package_t*) installed_pkgs->data;
358+ if (conf.pretend) {
359+ sprintf(msg, "Would unmerge %s-%s", installed_pkg->name,
360+ installed_pkg->version);
361+ einfo(msg);
362+ } else {
363+ if (tbz2_unmerge(installed_pkg) <= 0) rval = 1;
364+ if (rval==0) {
365+ einfo("Unmerge successful");
366+ } else {
367+ eerror("Unmerge failed!");
368+ }
369+ }
370+
371+ l = installed_pkgs->link;
372+ free(installed_pkgs->data);
373+ installed_pkgs = l;
374+ }
375+ if (should_free)
376+ free(index_pkg);
377+ return rval;
378+}
379+
380+static int
381+do_query(const package_t* user_pkg)
382+{
383+ einfo("Package query result\nQuery--");
384+ print_pkg(user_pkg);
385+ if (!user_pkg->index_pkg) {
386+ sprintf(msg, "Package not found in index: %s, continuing", user_pkg->name);
387+ einfo(msg);
388+ } else {
389+ einfo("Found package in index");
390+ print_pkg(user_pkg->index_pkg);
391+ }
392+ {
393+ llist_t *r, *l;
394+ einfo("Checking for installed version");
395+ r = find_package_on_disk(user_pkg);
396+ if (!r) { einfo("Not found"); }
397+ while(r) {
398+ einfo("Found installed package");
399+ print_pkg((package_t*)r->data);
400+ l = r->link;
401+ free(r->data);
402+ r = l;
403+ }
404+ }
405+ return 0;
406+}
407+
408+static int
409+do_sync(const package_t* user_pkg)
410+{
411+ eerror("Unable to sync");
412+ return 1;
413+}
414+
415+static int
416+do_list(const package_t* user_pkg)
417+{
418+ llist_t* r = find_package_on_disk(user_pkg), *l;
419+ while (r) {
420+ tbz2_list((package_t*)r->data);
421+ l = r->link;
422+ free(r->data);
423+ r = l;
424+ }
425+ return 0;
426+}
427+
428+static int
429+do_update(const package_t* user_pkg)
430+{
431+ eerror("Unable to update");
432+ return 1;
433+}
434+
435+static int
436+do_clean(const package_t* user_pkg)
437+{
438+ eerror("Unable to clean");
439+ return 1;
440+}
441+
442+
443+/* parseargs and similar ilk */
444+/* busybox has their own funny getopt structure, which depends on bits... */
445+#define EMERGE_HELP (1<<0)
446+#define EMERGE_DEBUG (1<<1)
447+#define EMERGE_PRETEND (1<<2)
448+#define EMERGE_VERBOSE (1<<3)
449+#define EMERGE_FETCH (1<<4)
450+#define EMERGE_USEPKGONLY (1<<5)
451+#define EMERGE_UNMERGE (1<<6)
452+#define EMERGE_QUERY (1<<7)
453+#define EMERGE_INFO (1<<8)
454+#define EMERGE_SYNC (1<<9)
455+#define EMERGE_LIST (1<<10)
456+#define EMERGE_UPDATE (1<<11)
457+#define EMERGE_CLEAN (1<<12)
458+
459+static struct option const emerge_long_options[] = {
460+ {"help", 0, 0, 'h'},
461+ {"debug", 0, 0, 'd'},
462+ {"pretend", 0, 0, 'p'},
463+ {"verbose", 0, 0, 'v'},
464+ {"fetch", 0, 0, 'f'},
465+ {"usepkgonly", 0, 0, 'K'},
466+ {"unmerge", 0, 0, 'C'},
467+ {"query", 0, 0, 'q'},
468+ {"info", 0, 0, 'i'},
469+ {"sync", 0, 0, 's'},
470+ {"list", 0, 0, 'l'},
471+ {"update", 0, 0, 'u'},
472+ {"clean", 0, 0, 'c'},
473+ {"root", 1, 0, 'R'},
474+ {"index", 1, 0, 'I'},
475+ {"pkgdir", 1, 0, 'P'},
476+ {"tmpdir", 1, 0, 'T'},
477+ {"binhost", 1, 0, 'B'},
478+ {NULL, 0, NULL, 0}
479+};
480+
481+#define OPTIONS_FLAGS "hdpvfKCqislucR:I:P:T:B:"
482+static void
483+parseargs(int argc, char *argv[])
484+{
485+ int optend;
486+ unsigned long opt;
487+ char *root=0, *pkgdir=0, *tmpdir=0, *binhost=0, *cindex=0;
488+ package_t* tmppkg;
489+ opterr = 0;
490+ /* this complementaly only works if a conflict is specified in both directions,
491+ thus f~q:q~f will block f & q from being specified together. that seems
492+ pretty wrong to me */
493+ bb_opt_complementaly = "f~Cqisluc:i~pfKCqsluc:q~f";
494+ bb_applet_long_options = emerge_long_options;
495+
496+ /* need to allocate these flags, not let bb do it! */
497+ /* need to allocate!! also, conf.index processing seems broken */
498+ root = pkgdir = tmpdir = binhost = 0;
499+ opt = bb_getopt_ulflags(argc, argv, OPTIONS_FLAGS,
500+ &root, &cindex, &pkgdir, &tmpdir, &binhost);
501+ if (root != NULL) {
502+ conf.root = xmalloc(strnlen(root, GEM_PATH_MAX));
503+ strncpy(conf.root, root, GEM_PATH_MAX);
504+ }
505+ if (pkgdir != NULL) {
506+ conf.pkgdir = xmalloc(strnlen(pkgdir, GEM_PATH_MAX));
507+ strncpy(conf.pkgdir, pkgdir, GEM_PATH_MAX);
508+ }
509+ if (tmpdir != NULL) {
510+ conf.tmpdir = xmalloc(strnlen(tmpdir, GEM_PATH_MAX));
511+ strncpy(conf.tmpdir, tmpdir, GEM_PATH_MAX);
512+ }
513+ if (binhost != NULL) {
514+ conf.binhost = xmalloc(strnlen(binhost, GEM_NAME_LEN));
515+ strncpy(conf.binhost, binhost, GEM_NAME_LEN);
516+ }
517+ if (cindex != NULL) {
518+ conf.index = xmalloc(strnlen(cindex, GEM_PATH_MAX));
519+ strncpy(conf.index, cindex, GEM_PATH_MAX);
520+ }
521+
522+ /* Check one and only one context option was given */
523+ /* this doesn't work... */
524+ if (opt & 0x80000000UL) {
525+ bb_printf("conflict!\n");
526+ bb_show_usage();
527+ }
528+
529+ if (opt & EMERGE_HELP)
530+ bb_show_usage();
531+
532+ /* runtime-configuration */
533+ if (opt & EMERGE_DEBUG)
534+ conf.debug = 1;
535+ if (opt & EMERGE_PRETEND)
536+ conf.pretend = 1;
537+ if (opt & EMERGE_VERBOSE)
538+ conf.verbose = 1;
539+ if (opt & EMERGE_USEPKGONLY)
540+ conf.usepkgonly = 1;
541+
542+ /* actions */
543+ if (opt & EMERGE_INFO
544+ || (argv[optind] && strncmp(argv[optind], "info", 4) == 0)) {
545+ /* info: perform info, then exit */
546+ do_info();
547+ exit(0);
548+ } else {
549+ if (opt & EMERGE_FETCH)
550+ action = do_fetch;
551+ else if (opt & EMERGE_UNMERGE)
552+ action = do_unmerge;
553+ else if (opt & EMERGE_QUERY)
554+ action = do_query;
555+ else if (opt & EMERGE_SYNC)
556+ action = do_sync;
557+ else if (opt & EMERGE_LIST)
558+ action = do_list;
559+ else if (opt & EMERGE_UPDATE)
560+ action = do_update;
561+ else if (opt & EMERGE_CLEAN)
562+ action = do_clean;
563+ else
564+ action = do_merge;
565+ }
566+
567+ /* this adds the remainder of the arguments (i.e. the packages) reversed, so they
568+ are processed in the order specified (which may be important) */
569+ optend = argc - 1;
570+
571+ while (optend >= optind) {
572+ if (strnlen(argv[optend], GEM_NAME_LEN) == GEM_NAME_LEN) {
573+ snprintf(msg, GEM_NAME_LEN, "Name too long: %s", argv[optend]);
574+ edie(msg);
575+ }
576+ tmppkg = decode_namespec(argv[optend]);
577+ if (!tmppkg) {
578+ snprintf(msg, GEM_NAME_LEN, "Unable to decode name %s", argv[optend]);
579+ edie(msg);
580+ }
581+ tmppkg->index_pkg=0;
582+ conf.packages = llist_add_to(conf.packages, (char *)tmppkg);
583+ optend--;
584+ ++conf.num_packages;
585+ }
586+}
587+
588+/* all the functions that start with parse_ are for parsing the Index file */
589+static void
590+parse_pkgname_version(package_t* pkg)
591+{
592+ int i = 0; char *c;
593+ while (msg[i] != ' ' && i < GEM_MLEN) ++i;
594+ ++i;
595+ if (i >= GEM_MLEN) edie("overflow!");
596+ c = &msg[i];
597+keep_looking:
598+ while (msg[i] != '-' && i < GEM_MLEN) ++i;
599+ ++i;
600+ if (i >= GEM_MLEN) edie("overflow looking for version");
601+ if (!isdigit(msg[i])) goto keep_looking;
602+ strncpy(pkg->name, c, i-5);
603+ c = &msg[i];
604+ strncpy(pkg->version, c, GEM_NAME_LEN);
605+ i = strnlen(c, GEM_NAME_LEN);
606+ pkg->version[i-1]=0;
607+}
608+
609+static void
610+parse_category(package_t* pkg)
611+{
612+ /* CATEGORY: sys-kernel */
613+ int i = 0; char *c;
614+ while (msg[i] != ' ') ++i;
615+ ++i;
616+ c = &msg[i];
617+ i = strnlen(c, GEM_NAME_LEN);
618+ c[i-1]=0;
619+ strncpy(pkg->category, c, i-1);
620+}
621+
622+static void
623+parse_depend_line(package_t* pkg, char* m)
624+{
625+ /* just strchr our way through it--> use m, not msg! */
626+ char *c, *d, *i=m;
627+ do {
628+ c = strchr(i, ' ');
629+ if (c != NULL) {
630+ d = xmalloc(c-i+1);
631+ if (d == NULL) edie("failed to alloc space for depend");
632+ strncpy(d, i, c-i);
633+ pkg->depends = llist_add_to(pkg->depends, d);
634+ ++c; i = c;
635+ }
636+ } while (c != NULL);
637+ /* do the last one too */
638+ d = xmalloc(strlen(i)+1);
639+ strcpy(d, i);
640+ pkg->depends = llist_add_to(pkg->depends, d);
641+
642+}
643+
644+/* this is out in static-land because both parse_depends and parse_line need to use it */
645+static FILE *index_file;
646+static void
647+parse_depends(package_t* pkg)
648+{
649+ int saw_end_of_line = 0, len;
650+ char *m, *l;
651+ static char tmp[GEM_NAME_LEN];
652+ /* skip over the RDEPEND: part */
653+ if ((m = strchr(msg, ':')) == NULL) edie("No RDEPEND?");
654+ ++m; ++m;
655+ while (!saw_end_of_line) {
656+ len = strnlen(msg, GEM_MLEN);
657+ /* it's ok to use msg here ... */
658+ if (msg[len-1] == '\n') {
659+ saw_end_of_line = 1;
660+ msg[len-1]=0; /* cut that end of line off */
661+ /* but parsing the line parses on m */
662+ parse_depend_line(pkg, m);
663+ } else {
664+ /* also ok here */
665+ l = rindex(msg, ' '); /* space before the last word */
666+ ++l;
667+ strncpy(tmp, l, GEM_NAME_LEN); /* len - l ? */
668+ --l; *l=0; /* now the line parser can't see the partial word */
669+ parse_depend_line(pkg, m);
670+ strncpy(msg, tmp, GEM_NAME_LEN); /* now msg has the partial word */
671+ len = strnlen(msg, GEM_NAME_LEN);
672+ l = &msg[len];
673+ if (fgets(l, GEM_MLEN-len, index_file) == NULL) edie("unexpect end of file (deps");
674+ /* msg doesn't have RDEPEND anymore, so parse at beginning of msg */
675+ m = &msg[0];
676+ }
677+ }
678+}
679+
680+static int
681+parse_line(package_t* pkg)
682+{ /* must return 1 when the whole package is ready, otherwise 0 (or edie()) */
683+ /* fortunately, the lines in each section have totally distinct beginnings! */
684+ if (msg[0] == '\n') return 0;
685+ if (msg[0] == 'P') parse_pkgname_version(pkg);
686+ else if (msg[0] == 'C' && msg[1] == 'A') parse_category(pkg);
687+ else if (msg[0] == 'C' && msg[1] == 'H') return 0; /* parse_chost(pkg); */
688+ else if (msg[0] == 'L') return 0; /* parse_license(pkg); */
689+ else if (msg[0] == 'C' && msg[1] == 'F') return 0; /* parse_cflags(pkg); */
690+ else if (msg[0] == 'R') parse_depends(pkg);
691+ else if (msg[0] == 'U') return 0; /* parse_use(pkg); */
692+ /* size is the very last entry, so it will return 1 */
693+ else if (msg[0] == 'S') return 1; /* parse_size(pkg); */
694+ else { edie("unexpected data in index file"); }
695+ return 0;
696+}
697+
698+static int
699+process_index(void)
700+{
701+ package_t *pkg = 0;
702+
703+ if ((index_file = bb_xfopen(conf.index, "r")) == 0)
704+ edie("Failed to open index file");
705+ if (conf.debug) einfo("*** *** Processing index file");
706+
707+ while (feof(index_file) != 1) {
708+ /* can we get a line? */
709+ if (fgets(msg, GEM_MLEN, index_file) != NULL) {
710+ /* do we have a package? */
711+ if (!pkg) {
712+ pkg = (package_t*) malloc(sizeof(package_t));
713+ memset(pkg, 0, sizeof(package_t));
714+ }
715+ /* is the pkg already complete? */
716+ if (parse_line(pkg)==1) {
717+ /* finish package! */
718+ if (conf.verbose)
719+ print_pkg(pkg);
720+ pkg_info.packages = llist_add_to(pkg_info.packages, (char *) pkg);
721+ pkg = 0;
722+ ++pkg_info.num_packages;
723+ }
724+ }
725+ }
726+ if (ferror(index_file) != 0) {
727+ edie("encountered error while processing index file");
728+ }
729+ if (bb_fclose_nonstdin(index_file) != 0) return 1;
730+ if (conf.debug) { einfo("*** *** Done processing index file"); }
731+ return 0;
732+}
733+
734+int
735+emerge_main(int argc, char **argv)
736+{
737+ char tmpp[GEM_PATH_MAX];
738+ unsigned int len; int i;
739+ llist_t *tp;
740+ package_t *package = 0;
741+
742+ if (argc < 2)
743+ bb_show_usage();
744+
745+ conf.verbose = 0;
746+ conf.debug = 0;
747+ conf.pretend = 0;
748+ conf.usepkgonly = 0;
749+ conf.packages = 0;
750+ conf.num_packages = 0;
751+ conf.index = 0;
752+
753+ /* command line overrides env vars. */
754+ conf.pkgdir = getenv("PKGDIR");
755+ conf.binhost = getenv("PORTAGE_BINHOST");
756+ conf.tmpdir = getenv("PORTAGE_TMPDIR");
757+ conf.root = getenv("ROOT");
758+ conf.index = getenv("INDEX_FILE");
759+ conf.pkg_dbdir = getenv("PKG_DBDIR");
760+
761+ parseargs(argc, argv);
762+
763+ /* now configurations may have some items, and some not. function may exit */
764+#undef FOO
765+#define FOO "Try adding it to your /etc/make.conf, exporting it as an environment variable, or specifying it on the command line"
766+ /* verify that environment variables exist before going on, fix them on disk if necessary */
767+ if (conf.pkgdir == 0)
768+ edie("PKGDIR is not set. " FOO);
769+ if (conf.binhost == 0)
770+ edie("PORTAGE_BINHOST is not set. " FOO);
771+ if (conf.tmpdir == 0)
772+ edie("PORTAGE_TMPDIR is not set. " FOO);
773+ if (conf.root == 0)
774+ edie("ROOT is not set. " FOO);
775+ if (conf.index == 0)
776+ edie("INDEX is not set. " FOO);
777+#undef FOO
778+ (void) tbz2pkg_init(&conf);
779+
780+
781+ /* make sure PKGDIR exists on disk */
782+ len = strnlen(conf.pkgdir, GEM_PATH_MAX);
783+ memset(tmpp, 0, sizeof(tmpp));
784+ strncpy(tmpp, conf.pkgdir, len);
785+ strncat(tmpp, "/All", GEM_PATH_MAX - 1 - len);
786+ if (!dir_exists(tmpp)) /* dir_exists checks R_OK, not W_OK...fix that later! */
787+ if (mkalldirs(tmpp) != 0)
788+ edie("FAILED to make PKGDIR/All");
789+
790+ /* that's all for configuration; let's parse out the index */
791+ pkg_info.searchable_packages=0;
792+ pkg_info.num_packages=0;
793+ process_index();
794+
795+ pkg_info.searchable_packages =
796+ (package_t**) xmalloc(pkg_info.num_packages*sizeof(package_t*));
797+ tp = pkg_info.packages;
798+ for (i = 0; i < pkg_info.num_packages; ++i) {
799+ pkg_info.searchable_packages[i] = (package_t*) tp->data;
800+ tp = tp->link;
801+ }
802+
803+ /* now we are all set up. perform the action */
804+ tp = conf.packages;
805+ while (tp != 0) {
806+ package = (package_t*)tp->data;
807+ if (conf.debug) {
808+ bb_printf("handling package:\n");
809+ print_pkg(package);
810+ }
811+ package->index_pkg=find_in_index(package);
812+ if (action(package) != 0) {
813+ sprintf(msg, "Failed on package %s", package->name);
814+ edie(msg);
815+ }
816+ package = 0;
817+ tp = tp->link;
818+ }
819+
820+ exit(EXIT_SUCCESS);
821+}
822diff -Nru --exclude=CVS --exclude=env.sh busybox-1.00/archival/gentoo_shared.c busybox/archival/gentoo_shared.c
823--- busybox-1.00/archival/gentoo_shared.c 1970-01-01 01:00:00.000000000 +0100
824+++ busybox/archival/gentoo_shared.c 2005-06-08 19:46:32.000000000 +0200
825@@ -0,0 +1,297 @@
826+/*
827+* Distributed under the terms of the GNU General Public License v2
828+* $Header: /home/collar_b/programs/cvs/busybox/archival/gentoo_shared.c,v 1.10 2005/06/08 17:46:32 collar_b Exp $
829+*
830+* gentoo_shared: functions that are used by both emerge.c and tbz2pkg.c
831+* reason: emerge.c can depend (Config.on) on tbz2pkg, but not the other
832+* direction too.
833+*
834+* Written by Benjamin Collar & Natanael Copa
835+* Copyright (C) 2005, Benjamin Collar, Natanael Copa
836+*
837+********************************************************************
838+* This program is free software; you can redistribute it and/or
839+* modify it under the terms of the GNU General Public License as
840+* published by the Free Software Foundation; either version 2 of the
841+* License, or (at your option) any later version.
842+*
843+* This program is distributed in the hope that it will be useful, but
844+* WITHOUT ANY WARRANTY; without even the implied warranty of
845+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
846+* General Public License for more details.
847+*
848+* You should have received a copy of the GNU General Public License
849+* along with this program; if not, write to the Free Software
850+* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
851+* MA 02111-1307, USA.
852+*/
853+
854+#include "gentoo_shared.h"
855+#include <ctype.h>
856+
857+char msg[GEM_MLEN]; /* useful for einfo, etc--just a buffer */
858+
859+void
860+einfo(char *str)
861+{
862+ bb_fprintf(stdout, ">>> %s\n", str);
863+}
864+
865+void
866+eerror(char *str)
867+{
868+ bb_fprintf(stderr, "!!! %s\n", str);
869+}
870+
871+void
872+edie(char *str)
873+{
874+ eerror(str);
875+ bb_error_msg_and_die("Quitting...");
876+}
877+
878+extern configurables_t conf;
879+
880+void
881+print_pkg(const package_t* pkg)
882+{
883+ llist_t* d=pkg->depends;
884+ bb_printf("Name: %s\n", pkg->name);
885+ bb_printf("Version: %s\n", pkg->version);
886+ bb_printf("Category: %s\n", pkg->category);
887+ if (conf.debug) {
888+ bb_printf("Modifiers: %s\n", pkg->modifier);
889+ }
890+ bb_printf("Depends: \n");
891+ while (d) {
892+ bb_printf(" %s\n", d->data);
893+ d = d->link;
894+ }
895+ bb_printf("\n");
896+}
897+
898+int
899+bfind_compare(const void* key, const void* try)
900+{
901+ const package_t* query = (const package_t*) key;
902+ const package_t **potential = (const package_t**) try;
903+ int match=0;
904+ match = strcmp(query->name, (*potential)->name);
905+ if (match == 0) {
906+ if (conf.debug) { bb_printf("got a name match...\n"); }
907+ /* if the names match, check that we're in the same cateogry */
908+ if (query->category[0]) {
909+ match = strcmp(query->category, (*potential)->category);
910+ if (match != 0) {
911+ /* category doesn't match -- need resolution from user*/
912+ sprintf(msg, "Found package name in multiple categories: (given) %s, (found)"
913+ " %s Please resolve manually with emerge ... category/package\n",
914+ query->category, (*potential)->category);
915+ edie(msg);
916+ }
917+ if (conf.debug) { bb_printf("got a category match\n"); }
918+ /* if category does match, check version */
919+ }
920+ if (query->version[0]) {
921+ match = strcmp(query->version, (*potential)->version);
922+ if (query->modifier[0]) {
923+ if (conf.debug)
924+ bb_printf("modifier processing engaged!\n");
925+ if (query->modifier[1] == '=' && match == 0) goto stop;
926+ if (query->modifier[0] == '=' && match == 0) goto stop;
927+ if (query->modifier[0] == '>' && match == -1) { match = 0; goto stop; }
928+ if (query->modifier[0] == '<' && match == 1) { match = 0; goto stop; }
929+ }
930+ if (conf.debug && match == 0) bb_printf("got version match\n");
931+ }
932+ }
933+stop:
934+ if (conf.debug) {
935+ bb_printf("compare result %d for\n", match);
936+ print_pkg(query);
937+ print_pkg(*potential);
938+ }
939+ return match;
940+}
941+
942+typedef struct pkgsearch {
943+ llist_t* results;
944+ const package_t* package;
945+} pkgsearch_t;
946+
947+int
948+findPkgVerAction(const char* fileName, struct stat* statbuf, void* userData)
949+{
950+ pkgsearch_t* sch = (pkgsearch_t*) userData;
951+ package_t* result;
952+ char *basec, *bname, *begin, *dirc, *dname;
953+ int retval=0, cmp;
954+ static char version[GEM_NAME_LEN];
955+ if (conf.debug) bb_printf("checking for pkg/version, got %s\n", fileName);
956+ version[0]=0;
957+ basec = strdup(fileName);
958+ bname = basename(basec);
959+ if (strstr(bname, sch->package->name) != bname) {
960+ free(basec);
961+ return 1;
962+ }
963+ /* get version from fileName */
964+ begin = bname;
965+ while (*begin != 0) {
966+ if (*begin == '-') {
967+ ++begin;
968+ if (isdigit(*begin)) {
969+ strcpy(version, begin);
970+ break;
971+ }
972+ } else {
973+ ++begin;
974+ }
975+ }
976+ cmp = strcmp(version, sch->package->version);
977+ if (
978+ (sch->package->modifier[1] == '=' && cmp == 0) ||
979+ (sch->package->modifier[0] == '<' && cmp == -1) ||
980+ (sch->package->modifier[0] == '>' && cmp == 1) ||
981+ (sch->package->modifier[0] == '>' && cmp == 1) ||
982+ (!sch->package->modifier[0]) /* && cmp == 0) */
983+ )
984+ {
985+ result = xmalloc(sizeof(package_t));
986+ memset(result, 0, sizeof(package_t));
987+ /* we can copy the given package, as long as we clear the modifiers */
988+ memcpy(result, sch->package, sizeof(package_t));
989+ result->modifier[0]=0; result->modifier[1]=0;
990+ strcpy(result->version, version);
991+ strcpy(result->disk_location, fileName);
992+ if (conf.debug) { bb_printf("found disk entry %s", result->disk_location); }
993+ /* get the directory name == category */
994+ dirc = strdup(fileName);
995+ dname = dirname(dirc);
996+ free(basec);
997+ basec = strdup(dname);
998+ bname = basename(basec);
999+ strcpy(result->category, bname);
1000+ if (conf.debug) { bb_printf("found disk package \n"); print_pkg(result); }
1001+ free(dirc);
1002+ sch->results = llist_add_to(sch->results, (char*) result);
1003+ retval = 0;
1004+ } else {
1005+ retval = 1;
1006+ }
1007+
1008+ free(basec);
1009+ return retval;
1010+
1011+}
1012+
1013+/* the result* list for this function is a (single) directory name--the one that matches! */
1014+int
1015+findCatAction(const char* fileName, struct stat* statbuf, void* userData)
1016+{
1017+ pkgsearch_t* sch = (pkgsearch_t*) userData;
1018+ char *basec, *bname;
1019+ int retval;
1020+ if (conf.debug) bb_printf("checking for category, got %s\n", fileName);
1021+ basec = strdup(fileName);
1022+ bname = basename(basec);
1023+ if (strcmp(bname, sch->package->category) == 0) {
1024+ /* this is our man */
1025+ /* recur from here into pkgs directory, look for right name (only 1) */
1026+ recursive_action(fileName, 1, 0, 0, 0, findPkgVerAction, userData);
1027+ retval=0;
1028+ } else {
1029+ retval=1;
1030+ }
1031+ free(basec);
1032+ return retval;
1033+}
1034+
1035+llist_t*
1036+find_package_on_disk(const package_t* package)
1037+{
1038+/* int recursive_action(const char *fileName, int recurse,
1039+ int followLinks, int depthFirst,
1040+ int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData),
1041+ int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData),
1042+ void* userData);
1043+*/
1044+ static pkgsearch_t ps; ps.results=0; ps.package=package;
1045+ if (!*package->category)
1046+ recursive_action(conf.pkg_dbdir, 1, 0, 0, 0, findPkgVerAction, (void*) &ps);
1047+ else
1048+ recursive_action(conf.pkg_dbdir, 1, 0, 0, 0, findCatAction, (void*) &ps);
1049+ return ps.results;
1050+}
1051+
1052+package_t*
1053+decode_namespec(char* namespec)
1054+{
1055+ /* on the command line or in the Package-depends, the form of a specification is
1056+ * emerge abc
1057+ * cat/abc
1058+ * >=cat/abc-1.3.4.5
1059+ * this function has to split all that up and return a new package_t (in char form)
1060+ */
1061+ package_t* ret = xmalloc(sizeof(package_t));
1062+ char *slash, *begin, first = namespec[0];
1063+ int provided_modifiers=0, provided_category=0;
1064+ memset(ret, 0, sizeof(package_t));
1065+ if (conf.debug) { sprintf(msg, "decoding namespec %s\n", namespec); einfo(msg); }
1066+ switch (first) {
1067+ case '>': case '<': case '=': case '!':
1068+ {
1069+ /* handle modifiers */
1070+ provided_modifiers=1;
1071+ ret->modifier[0]=first;
1072+ first = namespec[1];
1073+ if (first == '>' || first == '<' || first == '=' || first == '!') {
1074+ ret->modifier[1] = first;
1075+ begin = &namespec[2];
1076+ } else {
1077+ begin = &namespec[1];
1078+ }
1079+ break;
1080+ }
1081+ default:
1082+ begin = &namespec[0];
1083+ }
1084+ /* is there a slash (and thus a category & name?) */
1085+ /* process category */
1086+ if ((slash = strchr(begin, '/')) != 0) {
1087+ /* we have a slash, so there must be a category */
1088+ provided_category=1;
1089+ *slash = 0;
1090+ strcpy(ret->category, begin);
1091+ ++slash;
1092+ begin = slash;
1093+ } else {
1094+ slash = begin;
1095+ }
1096+ /* process name & version */
1097+ while (*begin != 0) {
1098+ if (*begin == '-') {
1099+ ++begin;
1100+ if (isdigit(*begin)) {
1101+ strcpy(ret->version, begin);
1102+ --begin;
1103+ *begin = 0;
1104+ break;
1105+ } else {
1106+ continue;
1107+ }
1108+ }
1109+ ++begin;
1110+ }
1111+ strcpy(ret->name, slash);
1112+ if (conf.debug) {
1113+ bb_printf("Decoded namespec to \n");
1114+ print_pkg(ret);
1115+ }
1116+ if (provided_modifiers && !provided_category) {
1117+ sprintf(msg, "If you use =!<>, you must specify category/app. error: %s", namespec);
1118+ edie(msg);
1119+ }
1120+
1121+ return ret;
1122+}
1123diff -Nru --exclude=CVS --exclude=env.sh busybox-1.00/archival/gentoo_shared.h busybox/archival/gentoo_shared.h
1124--- busybox-1.00/archival/gentoo_shared.h 1970-01-01 01:00:00.000000000 +0100
1125+++ busybox/archival/gentoo_shared.h 2005-06-08 20:16:26.000000000 +0200
1126@@ -0,0 +1,83 @@
1127+/*
1128+* Distributed under the terms of the GNU General Public License v2
1129+* $Header: /home/collar_b/programs/cvs/busybox/archival/gentoo_shared.h,v 1.8 2005/06/08 17:46:32 collar_b Exp $
1130+*
1131+* stuff that is shared between emerge.c and tbz2pkg.c
1132+*
1133+* Written by Benjamin Collar
1134+* Copyright (C) 2005, Benjamin Collar
1135+*
1136+********************************************************************
1137+* This program is free software; you can redistribute it and/or
1138+* modify it under the terms of the GNU General Public License as
1139+* published by the Free Software Foundation; either version 2 of the
1140+* License, or (at your option) any later version.
1141+*
1142+* This program is distributed in the hope that it will be useful, but
1143+* WITHOUT ANY WARRANTY; without even the implied warranty of
1144+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1145+* General Public License for more details.
1146+*
1147+* You should have received a copy of the GNU General Public License
1148+* along with this program; if not, write to the Free Software
1149+* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
1150+* MA 02111-1307, USA.
1151+*/
1152+
1153+#ifndef GENTOO_SHARED_H
1154+#define GENTOO_SHARED_H
1155+
1156+#include "busybox.h"
1157+#include <string.h>
1158+#include <stdio.h>
1159+
1160+#define GEM_PATH_MAX (PATH_MAX)
1161+#define GEM_NAME_LEN (32)
1162+#define GEM_MLEN (GEM_PATH_MAX+64)
1163+
1164+typedef struct configurables_s {
1165+ char *root;
1166+ char *index;
1167+ char *tmpdir;
1168+ char *binhost;
1169+ char *pkgdir;
1170+ char *pkg_dbdir; /* used by tbz2pkg only */
1171+ char *install_mask; /* used by tbz2pkg only */
1172+ int verbose;
1173+ int debug;
1174+ int pretend;
1175+ int usepkgonly;
1176+ llist_t *packages; /* the package-names given on the command line */
1177+ int num_packages; /* the number of package-names given */
1178+} configurables_t;
1179+
1180+
1181+typedef struct package_s {
1182+ llist_t *depends;
1183+ struct package_s* index_pkg;
1184+ char modifier[3]; /* things like >=, =, !, ~, etc that portage uses */
1185+ char version[GEM_NAME_LEN];
1186+ char category[GEM_NAME_LEN];
1187+ char name[GEM_NAME_LEN];
1188+ char disk_location[GEM_PATH_MAX];
1189+} package_t;
1190+
1191+
1192+extern char msg[GEM_MLEN]; /* useful for einfo, etc--just a buffer */
1193+void einfo(char* s); /* write some info, emerge style */
1194+void eerror(char* s); /* write an error, emerge style */
1195+void edie(char* s); /* write the error, then exit */
1196+
1197+/* use this function to bsearch the pkg_info.packages array (all packages in index)
1198+ * or to just compare two package_t's
1199+ * key is a package_t* you are searching for, try is package_t** -- a possible match
1200+ * this function is used in bsearch, but may also be used to compare two package_t's;
1201+ * it returns -1,0,1 as one would expect */
1202+int bfind_compare(const void* key, const void* try);
1203+void print_pkg(const package_t* pkg);
1204+package_t* decode_namespec(char* namespec);
1205+/* finds an installed package (or multiple, if modifiers are used) */
1206+llist_t* find_package_on_disk(const package_t* package);
1207+
1208+
1209+#endif
1210diff -Nru --exclude=CVS --exclude=env.sh busybox-1.00/archival/tbz2pkg.c busybox/archival/tbz2pkg.c
1211--- busybox-1.00/archival/tbz2pkg.c 1970-01-01 01:00:00.000000000 +0100
1212+++ busybox/archival/tbz2pkg.c 2005-06-08 20:17:34.000000000 +0200
1213@@ -0,0 +1,945 @@
1214+/*
1215+ * tbz2pkg, an installer for gentoo binary packages (tbz2)
1216+ * $Header: /home/collar_b/programs/cvs/busybox/archival/tbz2pkg.c,v 1.13 2005/06/08 18:17:34 collar_b Exp $
1217+ *
1218+ * Written by Natanael Copa
1219+ * Copyright (C) 2005 by Natanael Copa
1220+ * Extended by Benjamin Collar
1221+ * Parts Copyright (C) 2005 by Benjamin Collar
1222+ *
1223+ * Distributed under the terms of the GNU General Public License v2
1224+ *
1225+ * This program is free software; you can redistribute it and/or
1226+ * modify it under the terms of the GNU General Public License as
1227+ * published by the Free Software Foundation; either version 2 of the
1228+ * License, or (at your option) any later version.
1229+ *
1230+ * This program is distributed in the hope that it will be useful, but
1231+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1232+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1233+ * General Public License for more details.
1234+ *
1235+ * You should have received a copy of the GNU General Public License
1236+ * along with this program; if not, write to the Free Software
1237+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
1238+ * MA 02111-1307, USA.
1239+ */
1240+
1241+#include "busybox.h"
1242+#include <stdlib.h>
1243+#include <stdio.h>
1244+#include <string.h>
1245+#include <assert.h>
1246+#include <unistd.h>
1247+#include <sys/stat.h>
1248+#include <sys/types.h>
1249+#include <fcntl.h>
1250+
1251+#include <unarchive.h>
1252+#include <getopt.h>
1253+#include <errno.h>
1254+
1255+#include "tbz2pkg.h"
1256+
1257+
1258+#define BUFSIZE 32768
1259+#define PREBUFSIZE 7
1260+
1261+/* if BUFSIZE is smaller than XPACKSIZE, strange things could happen */
1262+#if (XPAKSIZE >= BUFSIZE)
1263+#error BUFSIZE must be bigger than XPAKSIZE
1264+#endif
1265+
1266+#define INDEX_LEN_OFFSET 8
1267+#define DATA_LEN_OFFSET (INDEX_LEN_OFFSET + 4)
1268+#define INDEX_OFFSET (DATA_LEN_OFFSET + 4)
1269+
1270+/* if the XPAK is bigger than 8MiB, something is wrong */
1271+#define FAR_TOO_BIG_XPAK (8192 * 1024)
1272+
1273+#define CHECKSUM_ALGO HASH_SHA1
1274+
1275+typedef struct xpak_s {
1276+ char *buffer; /* the raw xpak buffer */
1277+ int size;
1278+ int index_len;
1279+ int data_len;
1280+ int data_offset;
1281+} xpak_t;
1282+
1283+static configurables_t *conf;
1284+static char prebuf[PREBUFSIZE];
1285+static int presize=0; /* how much is in the prebuf? */
1286+static char root_dbdir[256];
1287+static char root_dbdir_pkg[256];
1288+static char root_dbdir_pkg_contents[256];
1289+
1290+static struct option const tbz2pkg_long_options[] = {
1291+ {"debug", 0, 0, 'd'},
1292+ {"help", 0, 0, 'h'},
1293+ {"install", 0, 0, 'i'},
1294+ {"install-mask", 1, 0, 'M'},
1295+ {"list", 0, 0, 'L'},
1296+ {"pretend", 0, 0, 'p'},
1297+ {"purge", 0, 0, 'P'},
1298+ {"root", 1, 0, 'R'},
1299+ {"verbose", 0, 0, 'v'},
1300+ {NULL, 0, NULL, 0}
1301+};
1302+
1303+#define TBZ2PKG_DEBUG (1<<0)
1304+#define TBZ2PKG_HELP (1<<1)
1305+#define TBZ2PKG_INSTALL (1<<2)
1306+#define TBZ2PKG_INSTALL_MASK (1<<3)
1307+#define TBZ2PKG_LIST (1<<4)
1308+#define TBZ2PKG_PRETEND (1<<5)
1309+#define TBZ2PKG_PURGE (1<<6)
1310+#define TBZ2PKG_ROOT (1<<7)
1311+#define TBZ2PKG_VERBOSE (1<<8)
1312+
1313+
1314+#define OPTIONS_FLAGS "dhiM:LpPR:v"
1315+
1316+
1317+configurables_t *tbz2pkg_init(configurables_t *myconf) {
1318+ snprintf(root_dbdir, sizeof(root_dbdir), "%s", myconf->pkg_dbdir);
1319+ return conf = myconf;
1320+}
1321+
1322+char *set_dbdir_pkg_char(const char *pkg) {
1323+ snprintf(root_dbdir_pkg, sizeof(root_dbdir_pkg), "%s/%s", root_dbdir, pkg);
1324+ strncpy(root_dbdir_pkg_contents, root_dbdir_pkg,
1325+ sizeof(root_dbdir_pkg_contents));
1326+ strncat(root_dbdir_pkg_contents, "/CONTENTS",
1327+ sizeof(root_dbdir_pkg_contents));
1328+ return root_dbdir_pkg;
1329+}
1330+
1331+char *set_dbdir_pkg(package_t *pkg) {
1332+ snprintf(root_dbdir_pkg, sizeof(root_dbdir_pkg), "%s", pkg->disk_location);
1333+ strncpy(root_dbdir_pkg_contents, root_dbdir_pkg,
1334+ sizeof(root_dbdir_pkg_contents));
1335+ strncat(root_dbdir_pkg_contents, "/CONTENTS",
1336+ sizeof(root_dbdir_pkg_contents));
1337+ return root_dbdir_pkg;
1338+}
1339+
1340+/*
1341+ convert a 4 byte big endian to int
1342+*/
1343+static int decodeint(const unsigned char *ptr) {
1344+ return (((int)ptr[0]) << 24) + (((int)ptr[1]) << 16)
1345+ + (((int)ptr[2]) << 8) + ((int)ptr[3]);
1346+}
1347+
1348+
1349+
1350+/*
1351+ return a string with the absolute path.
1352+*/
1353+char *mk_absolute_path(const char *path) {
1354+ static char fullpath[256]; /* maximun length of path */
1355+ if (strncmp(path, "./", 2) == 0)
1356+ snprintf(fullpath, sizeof(fullpath), "%s%s", conf->root, path+1);
1357+ else
1358+ snprintf(fullpath, sizeof(fullpath), "%s%s%s",
1359+ conf->root, (path[0] != '/') ? "/" : "", path);
1360+ return fullpath;
1361+}
1362+
1363+
1364+/* Creates a full path from a dbfile in the pkgdb */
1365+char *mk_dbdir_path(const char *package, const char *dbfile) {
1366+ static char path[256];
1367+ snprintf(path, sizeof(path), "%s/%s/%s",
1368+ mk_absolute_path(conf->pkg_dbdir), package, dbfile);
1369+ return path;
1370+}
1371+
1372+/*
1373+ finds the specified index and returns the value in a allocated buffer
1374+*/
1375+static char *xpak_get_data(const xpak_t *xpak, const char *key) {
1376+ int len;
1377+ int offset=INDEX_OFFSET;
1378+ char *pathname;
1379+ while (offset < xpak->index_len) {
1380+ if (offset + 4 > xpak->size)
1381+ bb_error_msg_and_die("xpak_get_data: problems with XPAK");
1382+ len = decodeint(xpak->buffer + offset);
1383+
1384+ /* pathname_len + pathname + data_offset + data_len */
1385+ if (offset + 4 + len + 4 + 4 > xpak->size)
1386+ return NULL;
1387+ pathname = bb_xstrndup(xpak->buffer + offset + 4, len);
1388+ if (strcmp(pathname, key) == 0) {
1389+ int data_offset = decodeint(xpak->buffer + offset + 4 + len);
1390+ int data_len = decodeint(xpak->buffer + offset + 8 + len);
1391+ char *p = xmalloc(data_len+1);
1392+ if (data_offset >= 0 && ((data_offset + data_len) < xpak->size)) {
1393+ memcpy(p, xpak->buffer + xpak->data_offset + data_offset,
1394+ data_len);
1395+ p[data_len] = '\0';
1396+ free(pathname);
1397+ return(p);
1398+ } else {
1399+ bb_error_msg_and_die("xpak_get_data: data_offset=%i, "
1400+ "data_offset+data_len=%i, xpak->size=%i",
1401+ data_offset, data_offset + data_len,
1402+ xpak->size);
1403+ }
1404+ }
1405+ free(pathname);
1406+ offset += 12 + len;
1407+ }
1408+ /* not found */
1409+ return NULL;
1410+}
1411+
1412+/*
1413+ allocate space for xpak->buffer and get the rest of the data stream
1414+ memory is allocated and pointer is stored in global variable xpak.
1415+
1416+ returns the size of xpak or -1 on error.
1417+*/
1418+int get_xpak(int src_fd, xpak_t *xpak, const char *restbuf, size_t restsize) {
1419+ static char readbuf[BUFSIZE];
1420+ int total = restsize;
1421+ int numread;
1422+
1423+ xpak->buffer = xmalloc(restsize);
1424+ memcpy(xpak->buffer, restbuf, restsize);
1425+
1426+ /* dump the rest of the data */
1427+ while((numread = read(src_fd, readbuf, BUFSIZE))) {
1428+ char *p;
1429+ p = xrealloc(xpak->buffer, total + numread);
1430+ xpak->buffer = p;
1431+ memcpy(xpak->buffer + total, readbuf, numread);
1432+ total += numread;
1433+ /* check that the XPAK is not unreasonable big */
1434+ if (total > FAR_TOO_BIG_XPAK) {
1435+ bb_error_msg_and_die("XPAK is unreasonable big. Giving up.");
1436+ }
1437+ }
1438+ xpak->size = total - 8; /* we skip the trailing [4 byte offset]STOP */
1439+ if (xpak->size < (INDEX_OFFSET + 8)) { /* the +8 is for the "XPAKSTOP" */
1440+ /* something is definitively wrong */
1441+ free(xpak->buffer);
1442+ xpak->buffer = NULL;
1443+ return -1;
1444+ }
1445+
1446+ xpak->index_len = decodeint(xpak->buffer + INDEX_LEN_OFFSET);
1447+ xpak->data_len = decodeint(xpak->buffer + DATA_LEN_OFFSET);
1448+ xpak->data_offset = INDEX_OFFSET + xpak->index_len;
1449+ if (xpak->data_offset + xpak->data_len + 8 > xpak->size) {
1450+ /* we are out of buffer */
1451+ free(xpak->buffer);
1452+ xpak->buffer=NULL;
1453+ return -1;
1454+ }
1455+ return xpak->size;
1456+}
1457+
1458+/*
1459+ flush buffer to file
1460+*/
1461+int flush_buf(const char *buf, int size, const char *filename) {
1462+ FILE *outfile;
1463+ int written;
1464+ outfile = bb_xfopen(filename, "w");
1465+ written = fwrite(buf, 1, size, outfile);
1466+ bb_fclose_nonstdin(outfile);
1467+ return written;
1468+}
1469+
1470+/*
1471+ read data from src_fd until we find a "XPAKPACK" string
1472+ returns numbers of byte available in buffer
1473+*/
1474+int read_to_xpak(int src_fd, char *buf, size_t size, xpak_t *xpak) {
1475+ int n;
1476+ int count, rest, avail;
1477+ char *p=buf;
1478+ char *found = NULL;
1479+
1480+ memcpy(buf, prebuf, presize);
1481+ n = size - presize; /* this is what we want to read */
1482+ assert(n>0);
1483+ if ((count = bb_xread(src_fd, buf+presize, n) + presize) == 0) {
1484+ /* we are done reading from file. no more data */
1485+ return 0;
1486+ }
1487+ presize=0;
1488+ avail=count;
1489+ rest=count;
1490+ while( ((p=memchr(p, 'X', rest)) != NULL) && (found == NULL) && rest) {
1491+ avail = p - buf; /* data available in buffer that is guaranteed to
1492+ not contain "XPAKPACK" */
1493+ rest = count - avail; /* the amount of data we need to examine */
1494+ if ( rest < PREBUFSIZE ) {
1495+ /*
1496+ we found 'X' but we don't have enough data left to check
1497+ the entire string. We save the data in prebuf for next read
1498+ */
1499+ memcpy(prebuf, p, rest);
1500+ presize=rest;
1501+ return avail;
1502+ }
1503+
1504+ if (strncmp(p, "XPAKPACK", rest)==0) {
1505+ /* ok guy's, we found the XPAKPACK */
1506+ found=p;
1507+ if (get_xpak(src_fd, xpak, p, rest)<0)
1508+ bb_error_msg_and_die("Problems with XPAK\n");
1509+ if (conf->debug) flush_buf(xpak->buffer, xpak->size, "/tmp/xpak");
1510+ return avail;
1511+ }
1512+
1513+ /* nothing here to see folks, move on (no XPAKPACK found)*/
1514+ p++;
1515+ rest--;
1516+ }
1517+ if (avail == 0 && found == NULL) {
1518+ bb_error_msg_and_die("No XPACK was found. sorry...\n");
1519+ }
1520+ return count;
1521+}
1522+
1523+
1524+/*
1525+ Extrackt the package from xpak. (CATEGORY/PF)
1526+*/
1527+char* xpak_get_package(xpak_t *xpak, char *package, int packagemax) {
1528+ char *cat, *pf, *eol;
1529+
1530+ if ((cat = xpak_get_data(xpak, "CATEGORY")) == NULL)
1531+ bb_error_msg_and_die("CATEGORY not found in XPAK");
1532+
1533+ if ((pf = xpak_get_data(xpak, "PF")) == NULL)
1534+ bb_error_msg_and_die("PF not found in XPAK");
1535+
1536+ if ((eol = strchr(cat, '\n')) != NULL) *eol = '\0';
1537+ if ((eol = strchr(pf, '\n')) != NULL) *eol = '\0';
1538+ snprintf(package, packagemax, "%s/%s", cat, pf);
1539+ free(cat);
1540+ free(pf);
1541+ return package;
1542+}
1543+
1544+/*
1545+ unpack the xpak to path
1546+*/
1547+int xpak_unpack(xpak_t *xpak, char *package, int package_bufsize) {
1548+ int len;
1549+ int offset=INDEX_OFFSET;
1550+ char *pathname;
1551+ int data_offset, data_len;
1552+
1553+ xpak_get_package(xpak, package, package_bufsize);
1554+ set_dbdir_pkg_char(package);
1555+ bb_make_directory(root_dbdir_pkg, -1, FILEUTILS_RECUR);
1556+
1557+ while (offset < xpak->index_len) {
1558+ char *key;
1559+ if (offset + 4 > xpak->size) return -1;
1560+ len = decodeint(xpak->buffer + offset);
1561+
1562+ /* pathname_len + pathname + data_offset + data_len */
1563+ if (offset + 4 + len + 4 + 4 > xpak->size) return -1;
1564+ if ((key = xmalloc(len + 1))==NULL) return -1;
1565+ memcpy(key, xpak->buffer + offset + 4, len);
1566+ key[len] = '\0';
1567+ pathname = mk_dbdir_path(package, key);
1568+ free(key);
1569+
1570+ data_offset = decodeint(xpak->buffer + offset + 4 + len);
1571+ data_len = decodeint(xpak->buffer + offset + 8 + len);
1572+
1573+ if ((data_offset >= 0) && ((data_offset + data_len) < xpak->size)) {
1574+ int i;
1575+ if (conf->debug) {
1576+ /* unpack the xpak if we are in debug mode */
1577+ if (conf->pretend)
1578+ i = xpak->size;
1579+ else
1580+ i = flush_buf(xpak->buffer
1581+ + xpak->data_offset
1582+ + data_offset,
1583+ data_len, pathname);
1584+ if (conf->verbose)
1585+ bb_printf("Writing %s: %i bytes\n", pathname, i);
1586+ }
1587+ } else {
1588+ bb_error_msg_and_die("Invalid XPAK.");
1589+ }
1590+ offset += 12 + len;
1591+ }
1592+ return 0;
1593+}
1594+
1595+/*
1596+ create a rejectlist for tar from install_mask
1597+*/
1598+llist_t *create_reject_list(const char *install_mask) {
1599+ char *tok, *mask;
1600+ llist_t *list = NULL;
1601+
1602+ mask = bb_xstrdup(install_mask);
1603+ /* according to man 3 strtok: "Never use these functions."
1604+ any alternative how this can easily be solved? */
1605+ tok=strtok(mask, " ");
1606+ while(tok != NULL) {
1607+ list = llist_add_to(list, bb_xstrdup(tok));
1608+ if (conf->debug) bb_printf("create_reject_list: added %s\n", tok);
1609+ tok = strtok(NULL, " ");
1610+ }
1611+ free(mask);
1612+ return list;
1613+}
1614+
1615+/*
1616+ for debugging stuff
1617+*/
1618+void dump_llist(llist_t *list) {
1619+ llist_t *item;
1620+ item = list;
1621+ while (item != NULL) {
1622+ bb_printf("dump_llist: %s\n", item->data);
1623+ item = item->link;
1624+ }
1625+}
1626+
1627+/*
1628+ this func unpacks (tar -xj) whatever comes from src_fd,
1629+ return the filelist to ret_fd and exit.
1630+ the XPAK is supposed to be stripped off from src_fd
1631+*/
1632+void tbz2_unpack_files(int src_fd, int ret_fd, const char *root_dir,
1633+ const char *install_mask) {
1634+ archive_handle_t *tar_handle = init_handle();
1635+ llist_t *item;
1636+
1637+ tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL;
1638+
1639+ if (install_mask != NULL) {
1640+ if (conf->debug)
1641+ bb_printf("creating reject list from '%s'\n", install_mask);
1642+ tar_handle->reject = create_reject_list(install_mask);
1643+ tar_handle->filter = filter_accept_reject_list;
1644+ if (conf->debug)
1645+ dump_llist(tar_handle->reject);
1646+ }
1647+ tar_handle->src_fd = src_fd;
1648+ tar_handle->seek = seek_by_char;
1649+ if (! conf->pretend) tar_handle->action_data = data_extract_all;
1650+
1651+ if (root_dir != NULL) {
1652+ if (chdir(root_dir))
1653+ bb_perror_msg_and_die("Couldnt chdir to %s", root_dir);
1654+ } else {
1655+ if (chdir("/"))
1656+ bb_perror_msg_and_die("Couldnt chdir to /");
1657+ }
1658+
1659+ while (get_header_tar_bz2(tar_handle) == EXIT_SUCCESS);
1660+
1661+ /* return the filelist */
1662+ for (item = tar_handle->passed; item != NULL; item = item->link) {
1663+ if (item->data != NULL) {
1664+ write(ret_fd, item->data, strlen(item->data));
1665+ write(ret_fd, "\0", 1);
1666+ }
1667+ }
1668+}
1669+
1670+
1671+/* those funcs are copied from coreutils/md5_sha1_sum.c */
1672+/* This might be useful elsewhere */
1673+static unsigned char *hash_bin_to_hex(unsigned char *hash_value,
1674+ unsigned char hash_length)
1675+{
1676+ int x, len, max;
1677+ unsigned char *hex_value;
1678+
1679+ max = (hash_length * 2) + 2;
1680+ hex_value = xmalloc(max);
1681+ for (x = len = 0; x < hash_length; x++) {
1682+ len += snprintf(hex_value + len, max - len, "%02x", hash_value[x]);
1683+ }
1684+ return (hex_value);
1685+}
1686+
1687+static uint8_t *hash_file(const char *filename, uint8_t hash_algo)
1688+{
1689+ static uint8_t hash_value_bin[22];
1690+ uint8_t *hash_value = NULL;
1691+ uint8_t hash_length;
1692+ int src_fd;
1693+
1694+ src_fd = open(filename, O_RDONLY);
1695+
1696+ if (hash_algo == HASH_MD5) {
1697+ hash_length = 16;
1698+ } else {
1699+ hash_length = 20;
1700+ }
1701+
1702+ /* hash_value_bin = xmalloc(hash_length); */
1703+
1704+ if ((src_fd != -1) && (hash_fd(src_fd, -1, hash_algo, hash_value_bin) != -2)) {
1705+ hash_value = hash_bin_to_hex(hash_value_bin, hash_length);
1706+ } else {
1707+ bb_perror_msg("%s", filename);
1708+ }
1709+ close(src_fd);
1710+ return(hash_value);
1711+}
1712+
1713+
1714+/*
1715+ write a line to CONTENTS file
1716+ returns size of file
1717+*/
1718+int write_line_to_contents(FILE *outf, const char *line) {
1719+ struct stat info;
1720+ char *fullpath = mk_absolute_path(line);
1721+
1722+ /* append to CONTENTS */
1723+ if (!conf->pretend) {
1724+ /* first we check if it is a link */
1725+ if (lstat(fullpath, &info) < 0) {
1726+ bb_perror_msg(fullpath);
1727+ return 0;
1728+ }
1729+ if (S_ISLNK(info.st_mode)) {
1730+ static char linkbuf[256];
1731+ readlink(fullpath, linkbuf, sizeof(linkbuf));
1732+ bb_fprintf(outf, "sym %s -> %s %i\n", line, linkbuf,
1733+ (int)info.st_mtime);
1734+ } else if (S_ISDIR(info.st_mode)) {
1735+ bb_fprintf(outf, "dir %s\n", line);
1736+ } else if (S_ISREG(info.st_mode)) {
1737+#ifdef CONFIG_FEATURE_MD5_SHA1_SUM_CHECK
1738+ char *hash = hash_file(fullpath, CHECKSUM_ALGO);
1739+ bb_fprintf(outf, "obj %s %s %i\n", line, hash, (int)info.st_mtime);
1740+ free(hash);
1741+#else
1742+ bb_fprintf(outf, "obj %s %i %i\n", line, (int)info.st_size,
1743+ (int)info.st_mtime);
1744+#endif
1745+ } else {
1746+ bb_fprintf(outf, "??? %s - %i\n", line,
1747+ (int)info.st_mtime);
1748+ }
1749+ }
1750+ if (conf->verbose) bb_printf(">>> %s\n", line);
1751+ return info.st_size;
1752+}
1753+
1754+/*
1755+ generate a CONTENTS file
1756+ returns numbers of lines written.
1757+*/
1758+int create_contents(int child_fd, const char *package) {
1759+ static char line[1024]; /* read buf */
1760+ char c;
1761+ int i = 0, line_count = 0, total_size = 0;
1762+ FILE *outf;
1763+
1764+ set_dbdir_pkg_char(package);
1765+ bb_make_directory(root_dbdir_pkg, -1, FILEUTILS_RECUR);
1766+
1767+ if (conf->root != NULL) chdir(conf->root); else chdir("/");
1768+
1769+ /* open the CONTENTS file */
1770+ outf = bb_xfopen(root_dbdir_pkg_contents, "w");
1771+
1772+ /* now we can read the file list from child */
1773+ /* we reuse the buffer */
1774+ while (read(child_fd, &c, 1)) {
1775+ if (i < (sizeof(line)-1)) /* buffer size checking... */
1776+ line[i++] = c;
1777+ else
1778+ line[i] = '\0';
1779+ if (c == '\0') {
1780+ total_size += write_line_to_contents(outf, line);
1781+ line_count++;
1782+ i = 0;
1783+ }
1784+ }
1785+ if (!conf->pretend) fclose(outf);
1786+ return total_size;
1787+}
1788+
1789+/* insert a string to llist, sorted by length. longest first */
1790+/* this code has to be buggy.... */
1791+llist_t *llist_insert_length_sorted(llist_t *list, char *data) {
1792+ llist_t *prev=NULL, *cur = list;
1793+ int data_len = strlen(data);
1794+
1795+ /* if this is the first element, create a new list */
1796+ if (list == NULL) return llist_add_to(list, data);
1797+
1798+ while ((cur != NULL) && (strlen(cur->data) > data_len)) {
1799+ prev = cur;
1800+ cur = cur->link;
1801+ }
1802+ if (cur == NULL) { /* this was the shortest, append to the end */
1803+ prev->link = llist_add_to(NULL, data);
1804+ } else {
1805+ if (prev != NULL)
1806+ prev->link = llist_add_to(cur, data);
1807+ else
1808+ return llist_add_to(cur, data);
1809+ }
1810+ return list;
1811+}
1812+
1813+/*
1814+ check if path is a link that points to dest.
1815+ returns nonzero if the dest correspond to the link.
1816+*/
1817+int check_link(const char *path, const char *dest) {
1818+ static char buf[256];
1819+ if (readlink(path, buf, sizeof(buf)) < 0) return 0;
1820+ return (strcmp(buf, dest) == 0);
1821+}
1822+
1823+/*
1824+ umerge a symlink.
1825+ modifies the passed "string". (replaces all spaces with \0 t be exact)
1826+*/
1827+int unmerge_sym(char *string) {
1828+ char *type = strtok(string, " ");
1829+ char *path = strtok(NULL, " ");
1830+ char *dest;
1831+ time_t mtime;
1832+ char *fullpath = mk_absolute_path(path);
1833+ static struct stat info;
1834+
1835+ strtok(NULL, " "); /* get the '->' */
1836+ dest = strtok(NULL, " ");
1837+ mtime = atoi(strtok(NULL, " "));
1838+ if (type == NULL || path == NULL) return 0;
1839+
1840+ lstat(fullpath, &info);
1841+ if (check_link(fullpath, dest) && (info.st_mtime == mtime)) {
1842+ /* remove it */
1843+ if (conf->verbose) bb_printf("<<< %s\n", path);
1844+ if (!conf->pretend && (unlink(fullpath) < 0))
1845+ bb_perror_msg("%s", fullpath);
1846+ else
1847+ return info.st_size;
1848+ } else {
1849+ if (conf->verbose) bb_printf("--- %s\n", path);
1850+ }
1851+
1852+ return 0;
1853+}
1854+
1855+/*
1856+ unmerge a file
1857+ modifies line. (replaces all spaces with \0 t be exact)
1858+ returns size of the file removed.
1859+*/
1860+int unmerge_obj(char *line) {
1861+ char *type = strtok(line, " ");
1862+ char *path = strtok(NULL, " ");
1863+ char *chksum = strtok(NULL, " ");
1864+ time_t mtime = atoi(strtok(NULL, " "));
1865+ static char fullpath[256];
1866+ static struct stat info;
1867+
1868+ if (type == NULL || path == NULL || chksum == NULL) return 0;
1869+
1870+ snprintf(fullpath, sizeof(fullpath), "%s%s%s",
1871+ conf->root, (path[0] != '/') ? "/" : "", path);
1872+
1873+ lstat(fullpath, &info);
1874+ /*
1875+ bb_printf("%s:%s contents(%i:%i) - stat(%i,%i)\n\n",
1876+ type, path, atoi(chksum), (int)mtime,
1877+ (int)info.st_size, (int)info.st_mtime);
1878+ */
1879+ /* currently the chksum is just the file size... */
1880+ if ((mtime == info.st_mtime) &&
1881+#ifdef CONFIG_FEATURE_MD5_SHA1_SUM_CHECK
1882+ (strcmp(chksum, hash_file(fullpath, CHECKSUM_ALGO)) == 0)
1883+ /* we should free the allocated mem from hash_file here... */
1884+#else
1885+ (atoi(chksum) == info.st_size)
1886+#endif
1887+ ) {
1888+ if (conf->verbose) bb_printf("<<< %s\n", path);
1889+ if (!conf->pretend && unlink(fullpath) < 0)
1890+ bb_perror_msg("%s", fullpath);
1891+ else {
1892+ return info.st_size;
1893+ }
1894+ } else {
1895+ if(conf->verbose) bb_printf("--- %s\n", path);
1896+ }
1897+ return 0;
1898+}
1899+
1900+/*
1901+ change dir where the CONTENTS are stored
1902+ return 0 on succes.
1903+*/ /*
1904+int ch_dbdir(const char *package) {
1905+ char path[256];
1906+ snprintf(path, sizeof(path), "%s/%s/%s",
1907+ conf->root, conf->pkg_dbdir, package);
1908+ return (chdir(mk_as_path(package)));
1909+}
1910+*/
1911+/*
1912+ Search unlink all files liste in list and destroy the list.
1913+ Data in the nodes is free'ed too.
1914+ returns number of destroyed items.
1915+*/
1916+int llist_rmdir_and_destroy(llist_t *list) {
1917+ llist_t *item = list;
1918+ int count = 0;
1919+ while (item != NULL) {
1920+ llist_t *tmp;
1921+ if (rmdir(mk_absolute_path(item->data)) == 0) {
1922+ count++;
1923+ if (conf->verbose) bb_printf("<<< %s\n", item->data);
1924+ } else {
1925+ if (conf->verbose) bb_printf("--- %s\n", item->data);
1926+ }
1927+ free(item->data);
1928+ tmp = item;
1929+ item = item->link;
1930+ free(tmp);
1931+ }
1932+ return count;
1933+}
1934+
1935+int tbz2_unmerge(package_t *package) {
1936+ FILE *inf;
1937+ static char line[256];
1938+ llist_t *dirs=NULL;
1939+ int total_removed = 0;
1940+
1941+ if (package == NULL) return -1;
1942+ set_dbdir_pkg(package);
1943+ /* check if file exist */
1944+ inf = bb_xfopen(root_dbdir_pkg_contents, "r");
1945+ chdir(conf->root);
1946+ while (fgets(line, sizeof(line), inf)) {
1947+ chomp(line);
1948+ if (strncmp(line, "dir", 3) == 0) {
1949+ /* we remove the dirs after files and sym's */
1950+ dirs = llist_insert_length_sorted(dirs, bb_xstrdup(line+4));
1951+ } else if (strncmp(line, "sym", 3) == 0) {
1952+ unmerge_sym(line);
1953+ } else {
1954+ unmerge_obj(line);
1955+ }
1956+ ++total_removed;
1957+ }
1958+ fclose(inf);
1959+ /* remove dirs */
1960+ if (conf->debug)
1961+ bb_fprintf(stderr, "removed %i dirs", llist_rmdir_and_destroy(dirs));
1962+ else
1963+ llist_rmdir_and_destroy(dirs);
1964+
1965+ remove_file(root_dbdir_pkg, FILEUTILS_FORCE|FILEUTILS_RECUR);
1966+ return total_removed;
1967+}
1968+
1969+/* list contents of package */
1970+void tbz2_list(package_t *package) {
1971+ FILE *inf;
1972+ static char line[256];
1973+
1974+ if (package == NULL) return;
1975+ set_dbdir_pkg(package);
1976+ inf = bb_xfopen(root_dbdir_pkg_contents, "r");
1977+ while (fgets(line, sizeof(line), inf)) {
1978+ char *path;
1979+ strtok(line, " "); /* the type */
1980+ path = strtok(NULL, " ");
1981+ chomp(path);
1982+ bb_printf("%s\n", path);
1983+ }
1984+ fclose(inf);
1985+}
1986+
1987+/*
1988+ reads and unpacks package from src_fd and store the
1989+ category/package-version information in buffer package.
1990+*/
1991+int tbz2_install(int src_fd, char *package, int package_size,
1992+ configurables_t *conf_ptr) {
1993+ int count, total=0;
1994+ static char buffer[BUFSIZE];
1995+ xpak_t xpak;
1996+ int pid;
1997+ int fd_to_child[2];
1998+ int fd_from_child[2]; /* this is the pipe where we get the file list
1999+ in return */
2000+ /* set the global variable conf */
2001+ conf = conf_ptr;
2002+
2003+ if ((pipe(fd_to_child) != 0) || (pipe(fd_from_child) != 0)) {
2004+ bb_perror_msg_and_die("Can't create pipe");
2005+ }
2006+
2007+ pid = fork();
2008+ if (pid == -1) {
2009+ bb_perror_msg_and_die("Fork failed");
2010+ }
2011+
2012+ if (pid == 0) {
2013+ /* child process */
2014+ close(fd_to_child[1]);
2015+ close(fd_from_child[0]);
2016+ tbz2_unpack_files(fd_to_child[0], fd_from_child[1],
2017+ conf->root, conf->install_mask);
2018+ close(fd_to_child[0]);
2019+ close(fd_from_child[1]);
2020+ exit(0);
2021+ }
2022+
2023+ /* parent process */
2024+ close(fd_to_child[0]); /* This is for writing to child */
2025+ close(fd_from_child[1]); /* and this is for reading */
2026+
2027+ while ( (count = read_to_xpak(src_fd, buffer, BUFSIZE, &xpak))) {
2028+ if (bb_full_write(fd_to_child[1], buffer, count) < count) {
2029+ bb_error_msg_and_die("unpacking archive failed");
2030+ }
2031+ total += count;
2032+ }
2033+ /* count contains the tar.bz2 size */
2034+
2035+ if (xpak.buffer == NULL) bb_error_msg_and_die("No XPAK found. Sorry.\n");
2036+ if (xpak_get_package(&xpak, package, package_size) == NULL)
2037+ bb_error_msg_and_die("Cound not extract package information from XPAK.\n");
2038+
2039+ /* now unmerge previously installed package */
2040+ /*
2041+ if (access(mk_dbdir_path(package, "CONTENTS"), R_OK) == 0)
2042+ tbz2_unmerge(package, conf);
2043+ */
2044+ if (!conf->pretend) xpak_unpack(&xpak, package, package_size);
2045+
2046+ count = create_contents(fd_from_child[0], package);
2047+ close(fd_from_child[0]);/* close the read pipe */
2048+ free(xpak.buffer);
2049+ return(count);
2050+}
2051+
2052+/*
2053+ Install from filename.
2054+ NULL or '-' means STDIN.
2055+*/
2056+int tbz2_install_file(char *file, configurables_t *myconf) {
2057+ char *display_name;
2058+ char package[256]; /* package name found in XPAK */
2059+ int src_fd, size;
2060+
2061+ tbz2pkg_init(myconf);
2062+ if ((file == NULL) || (strcmp(file, "-") == 0)) {
2063+ display_name = "STDIN";
2064+ src_fd = STDIN_FILENO;
2065+ } else {
2066+ display_name = file;
2067+ src_fd = bb_xopen(file, O_RDONLY);
2068+ }
2069+
2070+ if (myconf->verbose) bb_printf(">>> Unpacking %s\n", display_name);
2071+
2072+ size = tbz2_install(src_fd, package, sizeof(package), myconf);
2073+ if (size < 0 )
2074+ bb_error_msg_and_die("Package %s was not successfully"
2075+ " installed. Sorry.\n", display_name);
2076+ else
2077+ if (myconf->verbose)
2078+ bb_printf(">>> Package %s installed. %i bytes.\n\n",
2079+ package, size);
2080+
2081+ if (src_fd != STDIN_FILENO) close(src_fd);
2082+ return size;
2083+}
2084+
2085+/*
2086+ Main
2087+*/
2088+int tbz2pkg_main(int argc, char *argv[]) {
2089+ unsigned long opt;
2090+ configurables_t myconf;
2091+
2092+ myconf.root = NULL;
2093+ myconf.install_mask = NULL;
2094+ bb_applet_long_options = tbz2pkg_long_options;
2095+ opterr = 0;
2096+ opt = bb_getopt_ulflags(argc, argv, OPTIONS_FLAGS,
2097+ &myconf.install_mask,
2098+ &myconf.root);
2099+
2100+ bb_printf("%s\n", myconf.root);
2101+
2102+ if (opt & TBZ2PKG_HELP) bb_show_usage();
2103+
2104+ myconf.debug = (opt & TBZ2PKG_DEBUG);
2105+ myconf.pretend = (opt & TBZ2PKG_PRETEND);
2106+ myconf.verbose = (opt & TBZ2PKG_VERBOSE);
2107+
2108+ if (myconf.root == NULL) myconf.root = getenv("ROOT");
2109+ if (myconf.install_mask == NULL) myconf.install_mask = getenv("INSTALL_MASK");
2110+ if ((myconf.pkg_dbdir = getenv("PKG_DBDIR")) == NULL)
2111+ /* shouldn't this use myconf.root, not / ? */
2112+ myconf.pkg_dbdir = "/var/db/pkg";
2113+
2114+ if (myconf.debug)
2115+ bb_printf("root=%s, install_mask=%s, pkg_dbdir=%s\n",
2116+ myconf.root, myconf.install_mask, myconf.pkg_dbdir);
2117+
2118+ tbz2pkg_init(&myconf);
2119+ if (opt & TBZ2PKG_INSTALL) {
2120+ if (optind == argc) {
2121+ tbz2_install_file(NULL, &myconf);
2122+ } else {
2123+ int i, total_size=0;
2124+ for (i=optind; i < argc; i++)
2125+ total_size += tbz2_install_file(argv[i], &myconf);
2126+ if (myconf.verbose)
2127+ bb_printf(">>> Totally %i bytes installed.\n\n", total_size);
2128+ }
2129+ } else {
2130+ int i;
2131+ llist_t *results=0;
2132+ package_t *pkg, *tmppkg;
2133+ for (i=optind; i < argc; i++) {
2134+ pkg = decode_namespec(argv[i]);
2135+ results = find_package_on_disk(pkg);
2136+ while (results) {
2137+ tmppkg = (package_t*) results->data;
2138+ if (opt & TBZ2PKG_LIST) {
2139+ bb_printf(">>> Listing %s.\n", tmppkg->name);
2140+ tbz2_list(tmppkg);
2141+ } else if (opt & TBZ2PKG_PURGE) {
2142+ bb_printf(">>> Purging %s.\n", tmppkg->name);
2143+ tbz2_unmerge(tmppkg);
2144+ /* } else if (opt & TBZ2PKG_CHECK) {
2145+ bb_printf(">>> Checking %s.\n", pkg);
2146+ tbz2_check(pkg);
2147+ */
2148+ }
2149+ free(results->data);
2150+ results = results->link;
2151+ }
2152+ pkg = 0; results = 0;
2153+ }
2154+ }
2155+
2156+ return 0;
2157+}
2158+
2159diff -Nru --exclude=CVS --exclude=env.sh busybox-1.00/archival/tbz2pkg.h busybox/archival/tbz2pkg.h
2160--- busybox-1.00/archival/tbz2pkg.h 1970-01-01 01:00:00.000000000 +0100
2161+++ busybox/archival/tbz2pkg.h 2005-06-08 19:46:32.000000000 +0200
2162@@ -0,0 +1,35 @@
2163+/*
2164+* Distributed under the terms of the GNU General Public License v2
2165+* $Header: /home/collar_b/programs/cvs/busybox/archival/tbz2pkg.h,v 1.9 2005/06/08 17:46:32 collar_b Exp $
2166+*
2167+********************************************************************
2168+* This program is free software; you can redistribute it and/or
2169+* modify it under the terms of the GNU General Public License as
2170+* published by the Free Software Foundation; either version 2 of the
2171+* License, or (at your option) any later version.
2172+*
2173+* This program is distributed in the hope that it will be useful, but
2174+* WITHOUT ANY WARRANTY; without even the implied warranty of
2175+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2176+* General Public License for more details.
2177+*
2178+* You should have received a copy of the GNU General Public License
2179+* along with this program; if not, write to the Free Software
2180+* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
2181+* MA 02111-1307, USA.
2182+*/
2183+
2184+#ifndef TBZ2PKG_H
2185+#define TBZ2PKG_H
2186+
2187+#include "gentoo_shared.h"
2188+/* the data & decls here are shared by tbz2pkg and emerge */
2189+
2190+
2191+/* functions defined in tbz2pkg and used in emerge */
2192+int tbz2_install_file(char *file, configurables_t *myconf);
2193+int tbz2_unmerge(package_t *package);
2194+void tbz2_list(package_t *package);
2195+configurables_t *tbz2pkg_init(configurables_t *myconf);
2196+
2197+#endif /* TBZ2PKG_H */
2198diff -Nru --exclude=CVS --exclude=env.sh busybox-1.00/include/applets.h busybox/include/applets.h
2199--- busybox-1.00/include/applets.h 2004-08-27 01:01:34.000000000 +0200
2200+++ busybox/include/applets.h 2005-03-30 15:33:02.000000000 +0200
2201@@ -178,6 +178,9 @@
2202 #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS)
2203 APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)
2204 #endif
2205+#if defined(CONFIG_EMERGE)
2206+ APPLET(emerge, emerge_main, _BB_DIR_BIN, _BB_SUID_NEVER)
2207+#endif
2208 #ifdef CONFIG_ENV
2209 APPLET(env, env_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
2210 #endif
2211@@ -559,6 +562,9 @@
2212 #ifdef CONFIG_TAR
2213 APPLET(tar, tar_main, _BB_DIR_BIN, _BB_SUID_NEVER)
2214 #endif
2215+#ifdef CONFIG_TBZ2PKG
2216+ APPLET(tbz2pkg, tbz2pkg_main, _BB_DIR_BIN, _BB_SUID_NEVER)
2217+#endif
2218 #ifdef CONFIG_TEE
2219 APPLET(tee, tee_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
2220 #endif
2221diff -Nru --exclude=CVS --exclude=env.sh busybox-1.00/include/usage.h busybox/include/usage.h
2222--- busybox-1.00/include/usage.h 2004-09-14 18:23:56.000000000 +0200
2223+++ busybox/include/usage.h 2005-06-08 20:16:16.000000000 +0200
2224@@ -531,6 +531,30 @@
2225 "$ echo "Erik\\nis\\ncool"\n" \
2226 "Erik\\nis\\ncool\n")
2227
2228+#define emerge_trivial_usage \
2229+ "[-hdpvfKCqislucR:I:P:T:B:] package_name"
2230+#define emerge_full_usage \
2231+ "emerge is a utility to install, remove and manage Gentoo packages.\n" \
2232+ "Options:\n" \
2233+ "\t-h|--help : This help\n" \
2234+ "\t-d|--debug : set -x\n" \
2235+ "\t-p|--pretend : pretend only\n" \
2236+ "\t-v|--verbose : set verbose flag\n" \
2237+ "\t-f|--fetch : fetch binary files\n" \
2238+ "\t-K|--usepkgonly : use binary package\n" \
2239+ "\t-C|--unmerge : uninstall a binary package\n" \
2240+ "\t-q|--query : query a package\n" \
2241+ "\t--info|info : display info\n" \
2242+ "\t--sync : perform $opt operation\n" \
2243+ "\t--list : update index and list packages\n" \
2244+ "\t--update : update index file\n" \
2245+ "\t--clean : clean up tmpfiles\n" \
2246+ "\t--root=<dir> : define ROOT=\n" \
2247+ "\t--index=<file> : define INDEX_FILE=\n" \
2248+ "\t--pkgdir=<dir> : define PKGDIR=\n" \
2249+ "\t--tmpdir=<dir> : define PORTAGE_TMPDIR=\n" \
2250+ "\t--binhost=<url> : define PORTAGE_BINHOST=\n"
2251+
2252 #define env_trivial_usage \
2253 "[-iu] [-] [name=value]... [command]"
2254 #define env_full_usage \
2255@@ -2422,6 +2446,21 @@
2256 "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \
2257 "$ tar -cf /tmp/tarball.tar /usr/local\n"
2258
2259+#define tbz2pkg_trivial_usage \
2260+ "[OPTION]... [FILE|PKG_NAME]..."
2261+#define tbz2pkg_full_usage \
2262+ "Manage gentoo-created binary packages.\n\n" \
2263+ "Options:\n" \
2264+ "\t-d\tshow debug output\n" \
2265+ "\t-h\tshow this help information\n" \
2266+ "\t-i\tinstalled given binary packages (FILE)\n" \
2267+ "\t-M\tDon't install files that are masked by given regexp\n" \
2268+ "\t-L\tList contents of installed package(s) (PKG_NAME)\n" \
2269+ "\t-p\tPretend to do action (install, purge)\n" \
2270+ "\t-P\tUninstall package(s) (PKG_NAME)\n" \
2271+ "\t-R\tSet root directory to ROOT\n" \
2272+ "\t-v\tVerbose output\n"
2273+
2274 #define tee_trivial_usage \
2275 "[OPTION]... [FILE]..."
2276 #define tee_full_usage \