15 /* Stupid libc doesn't have a reliable way for use to know
16 * that libc5 is being used. Assume this is good enough */
17 #if !defined __GLIBC__ && !defined __UCLIBC__
18 #error It looks like you are using libc5, which does not support
19 #error tfind(). tfind() is used by busybox dpkg.
20 #error Please disable BB_DPKG. Sorry.
23 #define DEPENDSMAX 64 /* maximum number of depends we can handle */
25 /* Should we do full dependency checking? */
28 /* Should we do debugging? */
32 #define SYSTEM(x) do_system(x)
33 #define DPRINTF(fmt,args...) fprintf(stderr, fmt, ##args)
35 #define SYSTEM(x) system(x)
36 #define DPRINTF(fmt,args...) /* nothing */
40 extern int deb_extract(int optflags, const char *dir_name, const char *deb_filename);
41 static const int dpkg_deb_contents = 1;
42 static const int dpkg_deb_control = 2;
43 // const int dpkg_deb_info = 4;
44 static const int dpkg_deb_extract = 8;
45 static const int dpkg_deb_verbose_extract = 16;
46 static const int dpkg_deb_list = 32;
48 static const char statusfile[] = "/var/lib/dpkg/status.udeb";
49 static const char new_statusfile[] = "/var/lib/dpkg/status.udeb.new";
50 static const char bak_statusfile[] = "/var/lib/dpkg/status.udeb.bak";
52 static const char dpkgcidir[] = "/var/lib/dpkg/tmp.ci/";
54 static const char infodir[] = "/var/lib/dpkg/info/";
55 static const char udpkg_quiet[] = "UDPKG_QUIET";
57 //static const int status_wantstart = 0;
58 //static const int status_wantunknown = (1 << 0);
59 static const int status_wantinstall = (1 << 1);
60 //static const int status_wanthold = (1 << 2);
61 //static const int status_wantdeinstall = (1 << 3);
62 //static const int status_wantpurge = (1 << 4);
63 static const int status_wantmask = 31;
65 //static const int status_flagstart = 5;
66 static const int status_flagok = (1 << 5); /* 32 */
67 //static const int status_flagreinstreq = (1 << 6);
68 //static const int status_flaghold = (1 << 7);
69 //static const int status_flagholdreinstreq = (1 << 8);
70 static const int status_flagmask = 480;
72 //static const int status_statusstart = 9;
73 //static const int status_statusnoninstalled = (1 << 9); /* 512 */
74 static const int status_statusunpacked = (1 << 10);
75 static const int status_statushalfconfigured = (1 << 11);
76 static const int status_statusinstalled = (1 << 12);
77 static const int status_statushalfinstalled = (1 << 13);
78 //static const int status_statusconfigfiles = (1 << 14);
79 //static const int status_statuspostinstfailed = (1 << 15);
80 //static const int status_statusremovalfailed = (1 << 16);
81 static const int status_statusmask = 130560; /* i assume status_statusinstalled is supposed to be included */
83 static const char *statuswords[][10] = {
84 { (char *) 0, "unknown", "install", "hold", "deinstall", "purge", 0 },
85 { (char *) 5, "ok", "reinstreq", "hold", "hold-reinstreq", 0 },
86 { (char *) 9, "not-installed", "unpacked", "half-configured",
87 "installed", "half-installed", "config-files",
88 "post-inst-failed", "removal-failed", 0 }
91 static const int color_white = 0;
92 static const int color_grey = 1;
93 static const int color_black = 2;
96 typedef struct package_s {
103 int installer_menu_item;
104 unsigned long status;
105 char color; /* for topo-sort */
106 struct package_s *requiredfor[DEPENDSMAX];
107 unsigned short requiredcount;
108 struct package_s *next;
112 static int do_system(const char *cmd)
114 DPRINTF("cmd is %s\n", cmd);
118 #define do_system(cmd) system(cmd)
121 static int package_compare(const void *p1, const void *p2)
123 return strcmp(((package_t *)p1)->package,
124 ((package_t *)p2)->package);
127 static int remove_dpkgcidir()
129 char *rm_dpkgcidir = NULL;
131 rm_dpkgcidir = (char *) xmalloc(strlen(dpkgcidir) + 8);
132 strcpy(rm_dpkgcidir, "rm -rf ");
133 strcat(rm_dpkgcidir, dpkgcidir);
135 if (SYSTEM(rm_dpkgcidir) != 0) {
145 static char **depends_split(const char *dependsstr)
147 static char *dependsvec[DEPENDSMAX];
152 if (dependsstr == 0) {
156 p = strdup(dependsstr);
157 while (*p != 0 && *p != '\n') {
163 if (dependsvec[i] == 0) {
168 *p = 0; /* eat the space... */
179 /* Topological sort algorithm:
180 * ordered is the output list, pkgs is the dependency graph, pkg is
183 * recursively add all the adjacent nodes to the ordered list, marking
184 * each one as visited along the way
186 * yes, this algorithm looks a bit odd when all the params have the
189 static void depends_sort_visit(package_t **ordered, package_t *pkgs,
194 /* mark node as processing */
195 pkg->color = color_grey;
197 /* visit each not-yet-visited node */
198 for (i = 0; i < pkg->requiredcount; i++)
199 if (pkg->requiredfor[i]->color == color_white)
200 depends_sort_visit(ordered, pkgs, pkg->requiredfor[i]);
203 /* add it to the list */
204 newnode = (struct package_t *)xmalloc(sizeof(struct package_t));
205 /* make a shallow copy */
207 newnode->next = *ordered;
211 pkg->next = *ordered;
214 /* mark node as done */
215 pkg->color = color_black;
218 static package_t *depends_sort(package_t *pkgs)
220 /* TODO: it needs to break cycles in the to-be-installed package
222 package_t *ordered = NULL;
225 for (pkg = pkgs; pkg != 0; pkg = pkg->next) {
226 pkg->color = color_white;
228 for (pkg = pkgs; pkg != 0; pkg = pkg->next) {
229 if (pkg->color == color_white) {
230 depends_sort_visit(&ordered, pkgs, pkg);
234 /* Leaks the old list... return the new one... */
239 /* resolve package dependencies --
240 * for each package in the list of packages to be installed, we parse its
241 * dependency info to determine if the dependent packages are either
242 * already installed, or are scheduled to be installed. If both tests fail
245 * The algorithm here is O(n^2*m) where n = number of packages to be
246 * installed and m is the # of dependencies per package. Not a terribly
247 * efficient algorithm, but given that at any one time you are unlikely
248 * to install a very large number of packages it doesn't really matter
250 static package_t *depends_resolve(package_t *pkgs, void *status)
252 package_t *pkg, *chk;
258 for (pkg = pkgs; pkg != 0; pkg = pkg->next) {
259 dependsvec = depends_split(pkg->depends);
261 while (dependsvec[i] != 0) {
262 /* Check for dependencies; first look for installed packages */
263 dependpkg.package = dependsvec[i];
264 if ((found = tfind(&dependpkg, &status, package_compare)) == 0 ||
265 ((chk = *(package_t **)found) &&
266 (chk->status & (status_flagok | status_statusinstalled)) !=
267 (status_flagok | status_statusinstalled))) {
269 /* if it fails, we look through the list of packages we are going to
271 for (chk = pkgs; chk != 0; chk = chk->next) {
272 if (strcmp(chk->package, dependsvec[i]) == 0 || (chk->provides &&
273 strncmp(chk->provides, dependsvec[i], strlen(dependsvec[i])) == 0)) {
274 if (chk->requiredcount >= DEPENDSMAX) {
275 fprintf(stderr, "Too many dependencies for %s\n", chk->package);
279 chk->requiredfor[chk->requiredcount++] = pkg;
285 fprintf(stderr, "%s depends on %s, but it is not going to be installed\n", pkg->package, dependsvec[i]);
293 return depends_sort(pkgs);
297 /* Status file handling routines
299 * This is a fairly minimalistic implementation. there are two main functions
300 * that are supported:
302 * 1) reading the entire status file:
303 * the status file is read into memory as a binary-tree, with just the
304 * package and status info preserved
306 * 2) merging the status file
307 * control info from (new) packages is merged into the status file,
308 * replacing any pre-existing entries. when a merge happens, status info
309 * read using the status_read function is written back to the status file
311 static unsigned long status_parse(const char *line)
317 for (i = 0; i < 3; i++) {
318 if ((p = strchr(line, ' ')) != NULL) {
322 while (statuswords[i][j] != 0) {
323 if (strcmp(line, statuswords[i][j]) == 0) {
324 l |= (1 << ((int)statuswords[i][0] + j - 1));
330 if (statuswords[i][j] == 0) {
339 static const char *status_print(unsigned long flags)
341 /* this function returns a static buffer... */
342 static char buf[256];
346 for (i = 0; i < 3; i++) {
348 while (statuswords[i][j] != 0) {
349 if ((flags & (1 << ((int)statuswords[i][0] + j - 1))) != 0) {
350 strcat(buf, statuswords[i][j]);
351 if (i < 2) strcat(buf, " ");
356 if (statuswords[i][j] == 0) {
357 fprintf(stderr, "corrupted status flag!!\n");
366 * Read a control file (or a stanza of a status file) and parse it,
367 * filling parsed fields into the package structure
369 static int control_read(FILE *file, package_t *p)
373 while ((line = get_line_from_file(file)) != NULL) {
374 line[strlen(line)] = 0;
376 if (strlen(line) == 0) {
379 if (strstr(line, "Package: ") == line) {
380 p->package = strdup(line + 9);
382 if (strstr(line, "Status: ") == line) {
383 p->status = status_parse(line + 8);
385 if (strstr(line, "Depends: ") == line) {
386 p->depends = strdup(line + 9);
388 if (strstr(line, "Provides: ") == line) {
389 p->provides = strdup(line + 10);
391 if (strstr(line, "Description: ") == line) {
392 p->description = strdup(line + 13);
393 /* This is specific to the Debian Installer. Ifdef? */
395 if (strstr(line, "installer-menu-item: ") == line) {
396 p->installer_menu_item = atoi(line + 21);
398 /* TODO: localized descriptions */
404 static void *status_read(void)
408 package_t *m = 0, *p = 0, *t = 0;
410 if ((f = fopen(statusfile, "r")) == NULL) {
415 if (getenv(udpkg_quiet) == NULL) {
416 printf("(Reading database...)\n");
420 m = (package_t *)xmalloc(sizeof(package_t));
421 memset(m, 0, sizeof(package_t));
425 * If there is an item in the tree by this name,
426 * it must be a virtual package; insert real
427 * package in preference.
429 tdelete(m, &status, package_compare);
430 tsearch(m, &status, package_compare);
433 * A "Provides" triggers the insertion
434 * of a pseudo package into the status
437 p = (package_t *)xmalloc(sizeof(package_t));
438 memset(p, 0, sizeof(package_t));
439 p->package = strdup(m->provides);
441 t = *(package_t **)tsearch(p, &status, package_compare);
448 * Pseudo package status is the
449 * same as the status of the
450 * package providing it
451 * FIXME: (not quite right, if 2
452 * packages of different statuses
455 t->status = m->status;
467 static int status_merge(void *status, package_t *pkgs)
471 package_t *pkg = 0, *statpkg = 0;
475 if ((fin = fopen(statusfile, "r")) == NULL) {
479 if ((fout = fopen(new_statusfile, "w")) == NULL) {
480 perror(new_statusfile);
483 if (getenv(udpkg_quiet) == NULL) {
484 printf("(Updating database...)\n");
487 while (((line = get_line_from_file(fin)) != NULL) && !feof(fin)) {
488 line[strlen(line)] = 0; /* trim newline */
489 /* If we see a package header, find out if it's a package
490 * that we have processed. if so, we skip that block for
491 * now (write it at the end).
493 * we also look at packages in the status cache and update
494 * their status fields
496 if (strstr(line, "Package: ") == line) {
497 for (pkg = pkgs; pkg != 0 && strncmp(line + 9,
498 pkg->package, strlen(line) - 9) != 0;
501 locpkg.package = line + 9;
502 statpkg = tfind(&locpkg, &status, package_compare);
504 /* note: statpkg should be non-zero, unless the status
505 * file was changed while we are processing (no locking
506 * is currently done...
509 statpkg = *(package_t **)statpkg;
515 if (strstr(line, "Status: ") == line && statpkg != 0) {
516 snprintf(line, sizeof(line), "Status: %s",
517 status_print(statpkg->status));
524 // Print out packages we processed.
525 for (pkg = pkgs; pkg != 0; pkg = pkg->next) {
526 fprintf(fout, "Package: %s\nStatus: %s\n",
527 pkg->package, status_print(pkg->status));
529 fprintf(fout, "Depends: %s\n", pkg->depends);
531 fprintf(fout, "Provides: %s\n", pkg->provides);
532 if (pkg->installer_menu_item)
533 fprintf(fout, "installer-menu-item: %i\n", pkg->installer_menu_item);
534 if (pkg->description)
535 fprintf(fout, "Description: %s\n", pkg->description);
542 r = rename(statusfile, bak_statusfile);
544 r = rename(new_statusfile, statusfile);
550 static int is_file(const char *fn)
554 if (stat(fn, &statbuf) < 0) {
557 return S_ISREG(statbuf.st_mode);
560 static int dpkg_doconfigure(package_t *pkg)
566 DPRINTF("Configuring %s\n", pkg->package);
567 pkg->status &= status_statusmask;
568 snprintf(postinst, sizeof(postinst), "%s%s.postinst", infodir, pkg->package);
570 if (is_file(postinst)) {
571 snprintf(buf, sizeof(buf), "%s configure", postinst);
572 if ((r = do_system(buf)) != 0) {
573 fprintf(stderr, "postinst exited with status %d\n", r);
574 pkg->status |= status_statushalfconfigured;
578 pkg->status |= status_statusinstalled;
583 static int dpkg_dounpack(package_t *pkg)
588 char *src_file = NULL;
589 char *dst_file = NULL;
590 char *lst_file = NULL;
591 char *adminscripts[] = { "/prerm", "/postrm", "/preinst", "/postinst",
592 "/conffiles", "/md5sums", "/shlibs", "/templates" };
593 char buf[1024], buf2[1024];
595 DPRINTF("Unpacking %s\n", pkg->package);
599 deb_extract(dpkg_deb_extract, "/", pkg->file);
601 /* Installs the package scripts into the info directory */
602 for (i = 0; i < sizeof(adminscripts) / sizeof(adminscripts[0]); i++) {
603 /* The full path of the current location of the admin file */
604 src_file = xrealloc(src_file, strlen(dpkgcidir) + strlen(pkg->package) + strlen(adminscripts[i]) + 1);
605 strcpy(src_file, dpkgcidir);
606 strcat(src_file, pkg->package);
607 strcat(src_file, adminscripts[i]);
609 /* the full path of where we want the file to be copied to */
610 dst_file = xrealloc(dst_file, strlen(infodir) + strlen(pkg->package) + strlen(adminscripts[i]) + 1);
611 strcpy(dst_file, infodir);
612 strcat(dst_file, pkg->package);
613 strcat(dst_file, adminscripts[i]);
615 /* copy admin file to permanent home */
616 if (copy_file(src_file, dst_file, TRUE, FALSE, FALSE) < 0) {
617 error_msg_and_die("Cannot copy %s to %s ", buf, buf2);
620 /* create the list file */
621 lst_file = (char *) xmalloc(strlen(infodir) + strlen(pkg->package) + 6);
622 strcpy(lst_file, infodir);
623 strcat(lst_file, pkg->package);
624 strcat(lst_file, ".list");
625 outfp = freopen(lst_file, "w", stdout);
626 deb_extract(dpkg_deb_list, NULL, pkg->file);
627 stdout = freopen(NULL, "w", outfp);
635 pkg->status &= status_wantmask;
636 pkg->status |= status_wantinstall;
637 pkg->status &= status_flagmask;
638 pkg->status |= status_flagok;
639 pkg->status &= status_statusmask;
642 pkg->status |= status_statusunpacked;
644 pkg->status |= status_statushalfinstalled;
651 * Extract and parse the control.tar.gz from the specified package
653 static int dpkg_unpackcontrol(package_t *pkg)
659 /* clean the temp directory (dpkgcidir) be recreating it */
661 if (mkdir(dpkgcidir, S_IRWXU) != 0) {
667 * Get the package name from the file name,
668 * first remove the directories
670 if ((tmp_name = strrchr(pkg->file, '/')) == NULL) {
671 tmp_name = pkg->file;
675 /* now remove trailing version numbers etc */
676 length = strcspn(tmp_name, "_.");
677 pkg->package = (char *) xmalloc(length + 1);
678 /* store the package name */
679 strncpy(pkg->package, tmp_name, length);
681 /* work out the full extraction path */
682 tmp_name = (char *) xmalloc(strlen(dpkgcidir) + strlen(pkg->package) + 9);
683 memset(tmp_name, 0, strlen(dpkgcidir) + strlen(pkg->package) + 9);
684 strcpy(tmp_name, dpkgcidir);
685 strcat(tmp_name, pkg->package);
687 /* extract control.tar.gz to the full extraction path */
688 deb_extract(dpkg_deb_control, tmp_name, pkg->file);
690 /* parse the extracted control file */
691 strcat(tmp_name, "/control");
692 if ((file = fopen(tmp_name, "r")) == NULL) {
695 if (control_read(file, pkg) == EXIT_FAILURE) {
702 static int dpkg_unpack(package_t *pkgs, void *status)
707 for (pkg = pkgs; pkg != 0; pkg = pkg->next) {
708 if (dpkg_unpackcontrol(pkg) == EXIT_FAILURE) {
711 if ((r = dpkg_dounpack(pkg)) != 0 ) {
715 status_merge(status, pkgs);
721 static int dpkg_configure(package_t *pkgs, void *status)
727 for (pkg = pkgs; pkg != 0 && r == 0; pkg = pkg->next) {
728 found = tfind(pkg, &status, package_compare);
731 fprintf(stderr, "Trying to configure %s, but it is not installed\n", pkg->package);
734 /* configure the package listed in the status file;
735 * not pkg, as we have info only for the latter
738 r = dpkg_doconfigure(*(package_t **)found);
741 status_merge(status, 0);
746 static int dpkg_install(package_t *pkgs, void *status)
748 package_t *p, *ordered = 0;
750 /* Stage 1: parse all the control information */
751 for (p = pkgs; p != 0; p = p->next) {
752 if (dpkg_unpackcontrol(p) == EXIT_FAILURE) {
758 /* Stage 2: resolve dependencies */
760 ordered = depends_resolve(pkgs, status);
765 /* Stage 3: install */
766 for (p = ordered; p != 0; p = p->next) {
767 p->status &= status_wantmask;
768 p->status |= status_wantinstall;
770 /* for now the flag is always set to ok... this is probably
773 p->status &= status_flagmask;
774 p->status |= status_flagok;
776 DPRINTF("Installing %s\n", p->package);
777 if (dpkg_dounpack(p) != 0) {
780 if (dpkg_doconfigure(p) != 0) {
786 status_merge(status, pkgs);
793 static int dpkg_remove(package_t *pkgs, void *status)
797 for (p = pkgs; p != 0; p = p->next)
800 status_merge(status, 0);
805 extern int dpkg_main(int argc, char **argv)
809 package_t *p, *packages = NULL;
810 char *cwd = getcwd(0, 0);
815 /* Nasty little hack to "parse" long options. */
822 p = (package_t *)xmalloc(sizeof(package_t));
823 memset(p, 0, sizeof(package_t));
829 p->file = xmalloc(strlen(cwd) + strlen(*argv) + 2);
830 sprintf(p->file, "%s/%s", cwd, *argv);
832 p->package = strdup(*argv);
840 status = status_read();
844 return dpkg_install(packages, status);
846 return dpkg_remove(packages, status);
848 return dpkg_unpack(packages, status);
850 return dpkg_configure(packages, status);