1 diff -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
5 However it saves space as none of the extra dpkg-deb, ar or tar options are
6 needed, they are linked to internally.
9 + bool "emerge workalike for gentoo packages"
11 + depends on CONFIG_WGET && CONFIG_TBZ2PKG
13 + This allows busybox to fetch and install binary packages
14 + from the gentoo portage system.
21 Enable use of long options, increases size by about 400 Bytes
23 +config CONFIG_TBZ2PKG
26 + depends on CONFIG_FEATURE_TAR_BZIP2
28 + Install and uninstall gentoo binary packages
30 config CONFIG_UNCOMPRESS
33 diff -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
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
50 diff -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
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 $
58 +* emerge: a gentoo-emerge workalike for embedded systems, integrated
59 +* into the busybox suite
61 +* Written by Benjamin Collar
62 +* Copyright (C) 2005, Benjamin Collar
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.
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.
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.
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 :)
96 +#include <sys/types.h>
97 +#include <sys/stat.h>
98 +#include <sys/wait.h>
103 +#include "tbz2pkg.h"
105 +#define file_exists(f) (access(f, R_OK) == 0)
106 +#define dir_exists(f) (access(f, R_OK) == 0)
109 +typedef struct pkg_info_s {
111 + package_t** searchable_packages; /* sorted pointers to package names; use bsearch to find them */
112 + int num_packages; /* length of searchable_packages array */
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;
120 +/* some useful functions */
122 +mkalldirs(char *dir)
124 + return bb_make_directory(dir, -1, FILEUTILS_RECUR);
128 +find_in_index (package_t* pkg)
131 + result = bsearch((void*) pkg, (const void*) pkg_info.searchable_packages,
132 + pkg_info.num_packages, sizeof(package_t*), bfind_compare);
134 + return (*(package_t**)result);
140 +fetch_package(package_t* package)
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.
145 + /* append the category/package to the binhost to create the url */
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);
155 + sprintf(msg, "Would fetch %s/%s", package->category, pkgver);
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);
168 + /* further processing expects msg to contain path to downloaded file */
169 + /* REFACTOR THIS */
170 + strcpy(msg, target);
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);
177 + char *cmdline[] = { "wget", "-c", "-P", target, fullurl, 0 };
178 + pid_t child=fork();
179 + if ( child == 0 ) {
180 + execvp("/proc/self/exe", cmdline);
182 + int status, wgrval;
184 + if (WIFEXITED(status)) {
185 + wgrval = WEXITSTATUS(status);
187 + edie("Failed to fetch package");
189 + strcat(target, pkgver);
190 + sprintf(msg, "Package saved to %s", target);
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");
197 + /* save targetdir into msg; another function will use it */
198 + strcpy(msg, target);
207 +do_fetch(const package_t * user_pkg)
210 + package_t *dep_pkg, *index_pkg;
212 + index_pkg = user_pkg->index_pkg;
214 + eerror("Package not found in index, cannot fetch!");
217 + list = index_pkg->depends;
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);
227 + rval = rval ? rval : do_fetch(dep_pkg);
232 + if (conf.pretend) {
233 + sprintf(msg, "Would fetch package %s\n", user_pkg->name);
237 + return rval ? rval : fetch_package(index_pkg);
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);
253 +static int do_merge(const package_t* p);
256 +merge_should_install(package_t* p)
258 + static package_t tmppkg;
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;
275 +merge_deps(package_t* p)
277 + llist_t* list = p->depends;
278 + package_t* dep_pkg=0;
280 + sprintf(msg, "Merging dependencies of %s", p->name);
282 + if (conf.debug) { print_pkg(p); }
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);
291 + dep_pkg->index_pkg = find_in_index(dep_pkg);
292 + if (!dep_pkg->index_pkg) {
295 + rval = rval ? 1 : do_merge(dep_pkg);
301 + einfo("Done merging dependencies");
306 +do_merge(const package_t* user_pkg)
308 + package_t* index_pkg = user_pkg->index_pkg;
309 + sprintf(msg, "Merging package %s", user_pkg->name);
312 + eerror("Package not found in index");
315 + if (!merge_should_install(index_pkg)) {
316 + sprintf(msg, "Package %s already up-to-date", user_pkg->name);
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; }
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);
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);
336 +do_unmerge(const package_t* user_pkg)
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;
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);
347 + if (conf.pretend) {
348 + sprintf(msg, "Would unmerge %s", user_pkg->name);
352 + installed_pkgs = find_package_on_disk(index_pkg);
353 + if (!installed_pkgs) {
354 + einfo("Nothing to unmerge");
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);
363 + if (tbz2_unmerge(installed_pkg) <= 0) rval = 1;
365 + einfo("Unmerge successful");
367 + eerror("Unmerge failed!");
371 + l = installed_pkgs->link;
372 + free(installed_pkgs->data);
373 + installed_pkgs = l;
381 +do_query(const package_t* user_pkg)
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);
389 + einfo("Found package in index");
390 + print_pkg(user_pkg->index_pkg);
394 + einfo("Checking for installed version");
395 + r = find_package_on_disk(user_pkg);
396 + if (!r) { einfo("Not found"); }
398 + einfo("Found installed package");
399 + print_pkg((package_t*)r->data);
409 +do_sync(const package_t* user_pkg)
411 + eerror("Unable to sync");
416 +do_list(const package_t* user_pkg)
418 + llist_t* r = find_package_on_disk(user_pkg), *l;
420 + tbz2_list((package_t*)r->data);
429 +do_update(const package_t* user_pkg)
431 + eerror("Unable to update");
436 +do_clean(const package_t* user_pkg)
438 + eerror("Unable to clean");
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)
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'},
481 +#define OPTIONS_FLAGS "hdpvfKCqislucR:I:P:T:B:"
483 +parseargs(int argc, char *argv[])
487 + char *root=0, *pkgdir=0, *tmpdir=0, *binhost=0, *cindex=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;
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);
505 + if (pkgdir != NULL) {
506 + conf.pkgdir = xmalloc(strnlen(pkgdir, GEM_PATH_MAX));
507 + strncpy(conf.pkgdir, pkgdir, GEM_PATH_MAX);
509 + if (tmpdir != NULL) {
510 + conf.tmpdir = xmalloc(strnlen(tmpdir, GEM_PATH_MAX));
511 + strncpy(conf.tmpdir, tmpdir, GEM_PATH_MAX);
513 + if (binhost != NULL) {
514 + conf.binhost = xmalloc(strnlen(binhost, GEM_NAME_LEN));
515 + strncpy(conf.binhost, binhost, GEM_NAME_LEN);
517 + if (cindex != NULL) {
518 + conf.index = xmalloc(strnlen(cindex, GEM_PATH_MAX));
519 + strncpy(conf.index, cindex, GEM_PATH_MAX);
522 + /* Check one and only one context option was given */
523 + /* this doesn't work... */
524 + if (opt & 0x80000000UL) {
525 + bb_printf("conflict!\n");
529 + if (opt & EMERGE_HELP)
532 + /* runtime-configuration */
533 + if (opt & EMERGE_DEBUG)
535 + if (opt & EMERGE_PRETEND)
537 + if (opt & EMERGE_VERBOSE)
539 + if (opt & EMERGE_USEPKGONLY)
540 + conf.usepkgonly = 1;
543 + if (opt & EMERGE_INFO
544 + || (argv[optind] && strncmp(argv[optind], "info", 4) == 0)) {
545 + /* info: perform info, then exit */
549 + if (opt & EMERGE_FETCH)
551 + else if (opt & EMERGE_UNMERGE)
552 + action = do_unmerge;
553 + else if (opt & EMERGE_QUERY)
555 + else if (opt & EMERGE_SYNC)
557 + else if (opt & EMERGE_LIST)
559 + else if (opt & EMERGE_UPDATE)
560 + action = do_update;
561 + else if (opt & EMERGE_CLEAN)
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) */
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]);
576 + tmppkg = decode_namespec(argv[optend]);
578 + snprintf(msg, GEM_NAME_LEN, "Unable to decode name %s", argv[optend]);
581 + tmppkg->index_pkg=0;
582 + conf.packages = llist_add_to(conf.packages, (char *)tmppkg);
584 + ++conf.num_packages;
588 +/* all the functions that start with parse_ are for parsing the Index file */
590 +parse_pkgname_version(package_t* pkg)
592 + int i = 0; char *c;
593 + while (msg[i] != ' ' && i < GEM_MLEN) ++i;
595 + if (i >= GEM_MLEN) edie("overflow!");
598 + while (msg[i] != '-' && i < GEM_MLEN) ++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);
604 + strncpy(pkg->version, c, GEM_NAME_LEN);
605 + i = strnlen(c, GEM_NAME_LEN);
606 + pkg->version[i-1]=0;
610 +parse_category(package_t* pkg)
612 + /* CATEGORY: sys-kernel */
613 + int i = 0; char *c;
614 + while (msg[i] != ' ') ++i;
617 + i = strnlen(c, GEM_NAME_LEN);
619 + strncpy(pkg->category, c, i-1);
623 +parse_depend_line(package_t* pkg, char* m)
625 + /* just strchr our way through it--> use m, not msg! */
628 + c = strchr(i, ' ');
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);
636 + } while (c != NULL);
637 + /* do the last one too */
638 + d = xmalloc(strlen(i)+1);
640 + pkg->depends = llist_add_to(pkg->depends, d);
644 +/* this is out in static-land because both parse_depends and parse_line need to use it */
645 +static FILE *index_file;
647 +parse_depends(package_t* pkg)
649 + int saw_end_of_line = 0, len;
651 + static char tmp[GEM_NAME_LEN];
652 + /* skip over the RDEPEND: part */
653 + if ((m = strchr(msg, ':')) == NULL) edie("No RDEPEND?");
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);
665 + l = rindex(msg, ' '); /* space before the last word */
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);
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 */
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"); }
701 + package_t *pkg = 0;
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");
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? */
712 + pkg = (package_t*) malloc(sizeof(package_t));
713 + memset(pkg, 0, sizeof(package_t));
715 + /* is the pkg already complete? */
716 + if (parse_line(pkg)==1) {
717 + /* finish package! */
720 + pkg_info.packages = llist_add_to(pkg_info.packages, (char *) pkg);
722 + ++pkg_info.num_packages;
726 + if (ferror(index_file) != 0) {
727 + edie("encountered error while processing index file");
729 + if (bb_fclose_nonstdin(index_file) != 0) return 1;
730 + if (conf.debug) { einfo("*** *** Done processing index file"); }
735 +emerge_main(int argc, char **argv)
737 + char tmpp[GEM_PATH_MAX];
738 + unsigned int len; int i;
740 + package_t *package = 0;
748 + conf.usepkgonly = 0;
750 + conf.num_packages = 0;
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");
761 + parseargs(argc, argv);
763 + /* now configurations may have some items, and some not. function may exit */
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);
778 + (void) tbz2pkg_init(&conf);
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");
790 + /* that's all for configuration; let's parse out the index */
791 + pkg_info.searchable_packages=0;
792 + pkg_info.num_packages=0;
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;
803 + /* now we are all set up. perform the action */
804 + tp = conf.packages;
806 + package = (package_t*)tp->data;
808 + bb_printf("handling package:\n");
809 + print_pkg(package);
811 + package->index_pkg=find_in_index(package);
812 + if (action(package) != 0) {
813 + sprintf(msg, "Failed on package %s", package->name);
820 + exit(EXIT_SUCCESS);
822 diff -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
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 $
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
834 +* Written by Benjamin Collar & Natanael Copa
835 +* Copyright (C) 2005, Benjamin Collar, Natanael Copa
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.
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.
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.
854 +#include "gentoo_shared.h"
857 +char msg[GEM_MLEN]; /* useful for einfo, etc--just a buffer */
862 + bb_fprintf(stdout, ">>> %s\n", str);
868 + bb_fprintf(stderr, "!!! %s\n", str);
875 + bb_error_msg_and_die("Quitting...");
878 +extern configurables_t conf;
881 +print_pkg(const package_t* pkg)
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);
888 + bb_printf("Modifiers: %s\n", pkg->modifier);
890 + bb_printf("Depends: \n");
892 + bb_printf(" %s\n", d->data);
899 +bfind_compare(const void* key, const void* try)
901 + const package_t* query = (const package_t*) key;
902 + const package_t **potential = (const package_t**) try;
904 + match = strcmp(query->name, (*potential)->name);
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);
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);
917 + if (conf.debug) { bb_printf("got a category match\n"); }
918 + /* if category does match, check version */
920 + if (query->version[0]) {
921 + match = strcmp(query->version, (*potential)->version);
922 + if (query->modifier[0]) {
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; }
930 + if (conf.debug && match == 0) bb_printf("got version match\n");
935 + bb_printf("compare result %d for\n", match);
937 + print_pkg(*potential);
942 +typedef struct pkgsearch {
944 + const package_t* package;
948 +findPkgVerAction(const char* fileName, struct stat* statbuf, void* userData)
950 + pkgsearch_t* sch = (pkgsearch_t*) userData;
952 + char *basec, *bname, *begin, *dirc, *dname;
954 + static char version[GEM_NAME_LEN];
955 + if (conf.debug) bb_printf("checking for pkg/version, got %s\n", fileName);
957 + basec = strdup(fileName);
958 + bname = basename(basec);
959 + if (strstr(bname, sch->package->name) != bname) {
963 + /* get version from fileName */
965 + while (*begin != 0) {
966 + if (*begin == '-') {
968 + if (isdigit(*begin)) {
969 + strcpy(version, begin);
976 + cmp = strcmp(version, sch->package->version);
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) */
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);
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); }
1002 + sch->results = llist_add_to(sch->results, (char*) result);
1013 +/* the result* list for this function is a (single) directory name--the one that matches! */
1015 +findCatAction(const char* fileName, struct stat* statbuf, void* userData)
1017 + pkgsearch_t* sch = (pkgsearch_t*) userData;
1018 + char *basec, *bname;
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);
1036 +find_package_on_disk(const package_t* package)
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),
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);
1048 + recursive_action(conf.pkg_dbdir, 1, 0, 0, 0, findCatAction, (void*) &ps);
1049 + return ps.results;
1053 +decode_namespec(char* namespec)
1055 + /* on the command line or in the Package-depends, the form of a specification is
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)
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); }
1067 + case '>': case '<': case '=': case '!':
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];
1077 + begin = &namespec[1];
1082 + begin = &namespec[0];
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;
1090 + strcpy(ret->category, begin);
1096 + /* process name & version */
1097 + while (*begin != 0) {
1098 + if (*begin == '-') {
1100 + if (isdigit(*begin)) {
1101 + strcpy(ret->version, begin);
1111 + strcpy(ret->name, slash);
1113 + bb_printf("Decoded namespec to \n");
1116 + if (provided_modifiers && !provided_category) {
1117 + sprintf(msg, "If you use =!<>, you must specify category/app. error: %s", namespec);
1123 diff -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
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 $
1131 +* stuff that is shared between emerge.c and tbz2pkg.c
1133 +* Written by Benjamin Collar
1134 +* Copyright (C) 2005, Benjamin Collar
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.
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.
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.
1153 +#ifndef GENTOO_SHARED_H
1154 +#define GENTOO_SHARED_H
1156 +#include "busybox.h"
1157 +#include <string.h>
1160 +#define GEM_PATH_MAX (PATH_MAX)
1161 +#define GEM_NAME_LEN (32)
1162 +#define GEM_MLEN (GEM_PATH_MAX+64)
1164 +typedef struct configurables_s {
1170 + char *pkg_dbdir; /* used by tbz2pkg only */
1171 + char *install_mask; /* used by tbz2pkg only */
1176 + llist_t *packages; /* the package-names given on the command line */
1177 + int num_packages; /* the number of package-names given */
1181 +typedef struct package_s {
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];
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 */
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);
1210 diff -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
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 $
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
1223 + * Distributed under the terms of the GNU General Public License v2
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.
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.
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.
1241 +#include "busybox.h"
1242 +#include <stdlib.h>
1244 +#include <string.h>
1245 +#include <assert.h>
1246 +#include <unistd.h>
1247 +#include <sys/stat.h>
1248 +#include <sys/types.h>
1251 +#include <unarchive.h>
1252 +#include <getopt.h>
1255 +#include "tbz2pkg.h"
1258 +#define BUFSIZE 32768
1259 +#define PREBUFSIZE 7
1261 +/* if BUFSIZE is smaller than XPACKSIZE, strange things could happen */
1262 +#if (XPAKSIZE >= BUFSIZE)
1263 +#error BUFSIZE must be bigger than XPAKSIZE
1266 +#define INDEX_LEN_OFFSET 8
1267 +#define DATA_LEN_OFFSET (INDEX_LEN_OFFSET + 4)
1268 +#define INDEX_OFFSET (DATA_LEN_OFFSET + 4)
1270 +/* if the XPAK is bigger than 8MiB, something is wrong */
1271 +#define FAR_TOO_BIG_XPAK (8192 * 1024)
1273 +#define CHECKSUM_ALGO HASH_SHA1
1275 +typedef struct xpak_s {
1276 + char *buffer; /* the raw xpak buffer */
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];
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}
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)
1314 +#define OPTIONS_FLAGS "dhiM:LpPR:v"
1317 +configurables_t *tbz2pkg_init(configurables_t *myconf) {
1318 + snprintf(root_dbdir, sizeof(root_dbdir), "%s", myconf->pkg_dbdir);
1319 + return conf = myconf;
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;
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;
1341 + convert a 4 byte big endian to int
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]);
1351 + return a string with the absolute path.
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);
1358 + snprintf(fullpath, sizeof(fullpath), "%s%s%s",
1359 + conf->root, (path[0] != '/') ? "/" : "", path);
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);
1373 + finds the specified index and returns the value in a allocated buffer
1375 +static char *xpak_get_data(const xpak_t *xpak, const char *key) {
1377 + int offset=INDEX_OFFSET;
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);
1384 + /* pathname_len + pathname + data_offset + data_len */
1385 + if (offset + 4 + len + 4 + 4 > xpak->size)
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,
1395 + p[data_len] = '\0';
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,
1406 + offset += 12 + len;
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.
1416 + returns the size of xpak or -1 on error.
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;
1423 + xpak->buffer = xmalloc(restsize);
1424 + memcpy(xpak->buffer, restbuf, restsize);
1426 + /* dump the rest of the data */
1427 + while((numread = read(src_fd, readbuf, BUFSIZE))) {
1429 + p = xrealloc(xpak->buffer, total + numread);
1431 + memcpy(xpak->buffer + total, readbuf, 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.");
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;
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;
1455 + return xpak->size;
1459 + flush buffer to file
1461 +int flush_buf(const char *buf, int size, const char *filename) {
1464 + outfile = bb_xfopen(filename, "w");
1465 + written = fwrite(buf, 1, size, outfile);
1466 + bb_fclose_nonstdin(outfile);
1471 + read data from src_fd until we find a "XPAKPACK" string
1472 + returns numbers of byte available in buffer
1474 +int read_to_xpak(int src_fd, char *buf, size_t size, xpak_t *xpak) {
1476 + int count, rest, avail;
1478 + char *found = NULL;
1480 + memcpy(buf, prebuf, presize);
1481 + n = size - presize; /* this is what we want to read */
1483 + if ((count = bb_xread(src_fd, buf+presize, n) + presize) == 0) {
1484 + /* we are done reading from file. no more data */
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 ) {
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
1499 + memcpy(prebuf, p, rest);
1504 + if (strncmp(p, "XPAKPACK", rest)==0) {
1505 + /* ok guy's, we found the XPAKPACK */
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");
1513 + /* nothing here to see folks, move on (no XPAKPACK found)*/
1517 + if (avail == 0 && found == NULL) {
1518 + bb_error_msg_and_die("No XPACK was found. sorry...\n");
1525 + Extrackt the package from xpak. (CATEGORY/PF)
1527 +char* xpak_get_package(xpak_t *xpak, char *package, int packagemax) {
1528 + char *cat, *pf, *eol;
1530 + if ((cat = xpak_get_data(xpak, "CATEGORY")) == NULL)
1531 + bb_error_msg_and_die("CATEGORY not found in XPAK");
1533 + if ((pf = xpak_get_data(xpak, "PF")) == NULL)
1534 + bb_error_msg_and_die("PF not found in XPAK");
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);
1545 + unpack the xpak to path
1547 +int xpak_unpack(xpak_t *xpak, char *package, int package_bufsize) {
1549 + int offset=INDEX_OFFSET;
1551 + int data_offset, data_len;
1553 + xpak_get_package(xpak, package, package_bufsize);
1554 + set_dbdir_pkg_char(package);
1555 + bb_make_directory(root_dbdir_pkg, -1, FILEUTILS_RECUR);
1557 + while (offset < xpak->index_len) {
1559 + if (offset + 4 > xpak->size) return -1;
1560 + len = decodeint(xpak->buffer + offset);
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);
1567 + pathname = mk_dbdir_path(package, key);
1570 + data_offset = decodeint(xpak->buffer + offset + 4 + len);
1571 + data_len = decodeint(xpak->buffer + offset + 8 + len);
1573 + if ((data_offset >= 0) && ((data_offset + data_len) < xpak->size)) {
1575 + if (conf->debug) {
1576 + /* unpack the xpak if we are in debug mode */
1577 + if (conf->pretend)
1580 + i = flush_buf(xpak->buffer
1581 + + xpak->data_offset
1583 + data_len, pathname);
1584 + if (conf->verbose)
1585 + bb_printf("Writing %s: %i bytes\n", pathname, i);
1588 + bb_error_msg_and_die("Invalid XPAK.");
1590 + offset += 12 + len;
1596 + create a rejectlist for tar from install_mask
1598 +llist_t *create_reject_list(const char *install_mask) {
1600 + llist_t *list = NULL;
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, " ");
1616 + for debugging stuff
1618 +void dump_llist(llist_t *list) {
1621 + while (item != NULL) {
1622 + bb_printf("dump_llist: %s\n", item->data);
1623 + item = item->link;
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
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();
1637 + tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL;
1639 + if (install_mask != NULL) {
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;
1645 + dump_llist(tar_handle->reject);
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;
1651 + if (root_dir != NULL) {
1652 + if (chdir(root_dir))
1653 + bb_perror_msg_and_die("Couldnt chdir to %s", root_dir);
1656 + bb_perror_msg_and_die("Couldnt chdir to /");
1659 + while (get_header_tar_bz2(tar_handle) == EXIT_SUCCESS);
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);
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)
1677 + unsigned char *hex_value;
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]);
1684 + return (hex_value);
1687 +static uint8_t *hash_file(const char *filename, uint8_t hash_algo)
1689 + static uint8_t hash_value_bin[22];
1690 + uint8_t *hash_value = NULL;
1691 + uint8_t hash_length;
1694 + src_fd = open(filename, O_RDONLY);
1696 + if (hash_algo == HASH_MD5) {
1702 + /* hash_value_bin = xmalloc(hash_length); */
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);
1707 + bb_perror_msg("%s", filename);
1710 + return(hash_value);
1715 + write a line to CONTENTS file
1716 + returns size of file
1718 +int write_line_to_contents(FILE *outf, const char *line) {
1720 + char *fullpath = mk_absolute_path(line);
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);
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);
1742 + bb_fprintf(outf, "obj %s %i %i\n", line, (int)info.st_size,
1743 + (int)info.st_mtime);
1746 + bb_fprintf(outf, "??? %s - %i\n", line,
1747 + (int)info.st_mtime);
1750 + if (conf->verbose) bb_printf(">>> %s\n", line);
1751 + return info.st_size;
1755 + generate a CONTENTS file
1756 + returns numbers of lines written.
1758 +int create_contents(int child_fd, const char *package) {
1759 + static char line[1024]; /* read buf */
1761 + int i = 0, line_count = 0, total_size = 0;
1764 + set_dbdir_pkg_char(package);
1765 + bb_make_directory(root_dbdir_pkg, -1, FILEUTILS_RECUR);
1767 + if (conf->root != NULL) chdir(conf->root); else chdir("/");
1769 + /* open the CONTENTS file */
1770 + outf = bb_xfopen(root_dbdir_pkg_contents, "w");
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... */
1780 + total_size += write_line_to_contents(outf, line);
1785 + if (!conf->pretend) fclose(outf);
1786 + return total_size;
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);
1795 + /* if this is the first element, create a new list */
1796 + if (list == NULL) return llist_add_to(list, data);
1798 + while ((cur != NULL) && (strlen(cur->data) > data_len)) {
1802 + if (cur == NULL) { /* this was the shortest, append to the end */
1803 + prev->link = llist_add_to(NULL, data);
1806 + prev->link = llist_add_to(cur, data);
1808 + return llist_add_to(cur, data);
1814 + check if path is a link that points to dest.
1815 + returns nonzero if the dest correspond to the link.
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);
1825 + modifies the passed "string". (replaces all spaces with \0 t be exact)
1827 +int unmerge_sym(char *string) {
1828 + char *type = strtok(string, " ");
1829 + char *path = strtok(NULL, " ");
1832 + char *fullpath = mk_absolute_path(path);
1833 + static struct stat info;
1835 + strtok(NULL, " "); /* get the '->' */
1836 + dest = strtok(NULL, " ");
1837 + mtime = atoi(strtok(NULL, " "));
1838 + if (type == NULL || path == NULL) return 0;
1840 + lstat(fullpath, &info);
1841 + if (check_link(fullpath, dest) && (info.st_mtime == mtime)) {
1843 + if (conf->verbose) bb_printf("<<< %s\n", path);
1844 + if (!conf->pretend && (unlink(fullpath) < 0))
1845 + bb_perror_msg("%s", fullpath);
1847 + return info.st_size;
1849 + if (conf->verbose) bb_printf("--- %s\n", path);
1857 + modifies line. (replaces all spaces with \0 t be exact)
1858 + returns size of the file removed.
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;
1868 + if (type == NULL || path == NULL || chksum == NULL) return 0;
1870 + snprintf(fullpath, sizeof(fullpath), "%s%s%s",
1871 + conf->root, (path[0] != '/') ? "/" : "", path);
1873 + lstat(fullpath, &info);
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);
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... */
1885 + (atoi(chksum) == info.st_size)
1888 + if (conf->verbose) bb_printf("<<< %s\n", path);
1889 + if (!conf->pretend && unlink(fullpath) < 0)
1890 + bb_perror_msg("%s", fullpath);
1892 + return info.st_size;
1895 + if(conf->verbose) bb_printf("--- %s\n", path);
1901 + change dir where the CONTENTS are stored
1902 + return 0 on succes.
1904 +int ch_dbdir(const char *package) {
1906 + snprintf(path, sizeof(path), "%s/%s/%s",
1907 + conf->root, conf->pkg_dbdir, package);
1908 + return (chdir(mk_as_path(package)));
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.
1916 +int llist_rmdir_and_destroy(llist_t *list) {
1917 + llist_t *item = list;
1919 + while (item != NULL) {
1921 + if (rmdir(mk_absolute_path(item->data)) == 0) {
1923 + if (conf->verbose) bb_printf("<<< %s\n", item->data);
1925 + if (conf->verbose) bb_printf("--- %s\n", item->data);
1929 + item = item->link;
1935 +int tbz2_unmerge(package_t *package) {
1937 + static char line[256];
1938 + llist_t *dirs=NULL;
1939 + int total_removed = 0;
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)) {
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);
1954 + unmerge_obj(line);
1961 + bb_fprintf(stderr, "removed %i dirs", llist_rmdir_and_destroy(dirs));
1963 + llist_rmdir_and_destroy(dirs);
1965 + remove_file(root_dbdir_pkg, FILEUTILS_FORCE|FILEUTILS_RECUR);
1966 + return total_removed;
1969 +/* list contents of package */
1970 +void tbz2_list(package_t *package) {
1972 + static char line[256];
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)) {
1979 + strtok(line, " "); /* the type */
1980 + path = strtok(NULL, " ");
1982 + bb_printf("%s\n", path);
1988 + reads and unpacks package from src_fd and store the
1989 + category/package-version information in buffer package.
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];
1997 + int fd_to_child[2];
1998 + int fd_from_child[2]; /* this is the pipe where we get the file list
2000 + /* set the global variable conf */
2003 + if ((pipe(fd_to_child) != 0) || (pipe(fd_from_child) != 0)) {
2004 + bb_perror_msg_and_die("Can't create pipe");
2009 + bb_perror_msg_and_die("Fork failed");
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]);
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 */
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");
2033 + /* count contains the tar.bz2 size */
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");
2039 + /* now unmerge previously installed package */
2041 + if (access(mk_dbdir_path(package, "CONTENTS"), R_OK) == 0)
2042 + tbz2_unmerge(package, conf);
2044 + if (!conf->pretend) xpak_unpack(&xpak, package, package_size);
2046 + count = create_contents(fd_from_child[0], package);
2047 + close(fd_from_child[0]);/* close the read pipe */
2048 + free(xpak.buffer);
2053 + Install from filename.
2054 + NULL or '-' means STDIN.
2056 +int tbz2_install_file(char *file, configurables_t *myconf) {
2057 + char *display_name;
2058 + char package[256]; /* package name found in XPAK */
2061 + tbz2pkg_init(myconf);
2062 + if ((file == NULL) || (strcmp(file, "-") == 0)) {
2063 + display_name = "STDIN";
2064 + src_fd = STDIN_FILENO;
2066 + display_name = file;
2067 + src_fd = bb_xopen(file, O_RDONLY);
2070 + if (myconf->verbose) bb_printf(">>> Unpacking %s\n", display_name);
2072 + size = tbz2_install(src_fd, package, sizeof(package), myconf);
2074 + bb_error_msg_and_die("Package %s was not successfully"
2075 + " installed. Sorry.\n", display_name);
2077 + if (myconf->verbose)
2078 + bb_printf(">>> Package %s installed. %i bytes.\n\n",
2081 + if (src_fd != STDIN_FILENO) close(src_fd);
2088 +int tbz2pkg_main(int argc, char *argv[]) {
2089 + unsigned long opt;
2090 + configurables_t myconf;
2092 + myconf.root = NULL;
2093 + myconf.install_mask = NULL;
2094 + bb_applet_long_options = tbz2pkg_long_options;
2096 + opt = bb_getopt_ulflags(argc, argv, OPTIONS_FLAGS,
2097 + &myconf.install_mask,
2100 + bb_printf("%s\n", myconf.root);
2102 + if (opt & TBZ2PKG_HELP) bb_show_usage();
2104 + myconf.debug = (opt & TBZ2PKG_DEBUG);
2105 + myconf.pretend = (opt & TBZ2PKG_PRETEND);
2106 + myconf.verbose = (opt & TBZ2PKG_VERBOSE);
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";
2115 + bb_printf("root=%s, install_mask=%s, pkg_dbdir=%s\n",
2116 + myconf.root, myconf.install_mask, myconf.pkg_dbdir);
2118 + tbz2pkg_init(&myconf);
2119 + if (opt & TBZ2PKG_INSTALL) {
2120 + if (optind == argc) {
2121 + tbz2_install_file(NULL, &myconf);
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);
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);
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);
2149 + free(results->data);
2150 + results = results->link;
2152 + pkg = 0; results = 0;
2159 diff -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
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 $
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.
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.
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.
2187 +#include "gentoo_shared.h"
2188 +/* the data & decls here are shared by tbz2pkg and emerge */
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);
2197 +#endif /* TBZ2PKG_H */
2198 diff -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
2202 #if defined(CONFIG_FEATURE_GREP_EGREP_ALIAS)
2203 APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN, _BB_SUID_NEVER)
2205 +#if defined(CONFIG_EMERGE)
2206 + APPLET(emerge, emerge_main, _BB_DIR_BIN, _BB_SUID_NEVER)
2209 APPLET(env, env_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
2213 APPLET(tar, tar_main, _BB_DIR_BIN, _BB_SUID_NEVER)
2215 +#ifdef CONFIG_TBZ2PKG
2216 + APPLET(tbz2pkg, tbz2pkg_main, _BB_DIR_BIN, _BB_SUID_NEVER)
2219 APPLET(tee, tee_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
2221 diff -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")
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" \
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"
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"
2259 +#define tbz2pkg_trivial_usage \
2260 + "[OPTION]... [FILE|PKG_NAME]..."
2261 +#define tbz2pkg_full_usage \
2262 + "Manage gentoo-created binary packages.\n\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"
2274 #define tee_trivial_usage \
2275 "[OPTION]... [FILE]..."
2276 #define tee_full_usage \