]>
Commit | Line | Data |
---|---|---|
5e993f12 | 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 | |
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 | |
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 | |
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 | ||
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 | |
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 | +} | |
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 | |
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 | +} | |
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 | |
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 | |
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 | |
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 | + | |
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 | |
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 */ | |
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 | |
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 | |
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") | |
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 \ |