root/trunk/third/nautilus/components/services/install/lib/eazel-install-rpm-glue.c @ 15547

Revision 15547, 15.0 KB (checked in by ghudson, 9 years ago)

This commit was generated by cvs2svn to compensate for changes in r15546,
which included commits to RCS files with non-trunk default branches.

Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/*
3 * Copyright (C) 2000 Eazel, Inc
4 * Copyright (C) 1998-1999 James Henstridge
5 * Copyright (C) 1998 Red Hat Software, Inc.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 *
22 * Authors: J Shane Culpepper <pepper@eazel.com>
23 *          Eskil Heyn Olsen  <eskil@eazel.com>
24 */
25
26#include "eazel-install-rpm-glue.h"
27#include "eazel-install-public.h"
28#include "eazel-install-private.h"
29#include "eazel-install-logic.h"
30
31#include <libtrilobite/trilobite-core-utils.h>
32#include <libtrilobite/trilobite-md5-tools.h>
33
34#include <rpm/rpmlib.h>
35#include <string.h>
36#include <time.h>
37
38#include <ctype.h>
39
40#include <errno.h>
41#include <sys/stat.h>
42#include <sys/types.h>
43#include <fcntl.h>
44#include <unistd.h>
45#ifdef EAZEL_INSTALL_SLIM
46#include <sys/wait.h>
47#endif
48
49#include "eazel-package-system.h"
50
51/* WAAAAAAHH! */
52#include "eazel-package-system-rpm3.h"
53#include "eazel-package-system-rpm3-private.h"
54
55PackageData* packagedata_new_from_rpm_conflict (struct rpmDependencyConflict);
56PackageData* packagedata_new_from_rpm_conflict_reversed (struct rpmDependencyConflict);
57
58PackageData*
59packagedata_new_from_rpm_conflict (struct rpmDependencyConflict conflict) 
60{
61        PackageData *result;
62       
63        result = packagedata_new ();
64
65        result->name = g_strdup (conflict.needsName);
66        result->version = (conflict.needsVersion && (strlen (conflict.needsVersion) > 1)) ? g_strdup (conflict.needsVersion) : NULL;
67        return result;
68}
69
70PackageData*
71packagedata_new_from_rpm_conflict_reversed (struct rpmDependencyConflict conflict) 
72{
73        PackageData *result;
74       
75        result = packagedata_new ();
76
77        result->name = g_strdup (conflict.byName);
78        result->version = (conflict.byVersion && (strlen (conflict.byVersion) > 1)) ? g_strdup (conflict.byVersion) : NULL;
79        return result;
80}
81
82/*
83  Adds the headers to the package system set
84 */
85static void
86eazel_install_add_to_rpm_set (EazelInstall *service,
87                              rpmTransactionSet set, 
88                              GList **packages,
89                              GList **failed)
90
91{
92        GList *iterator;
93        GList *tmp_failed;
94        int interface_flags;
95
96        g_assert (packages!=NULL);
97        g_assert (*packages!=NULL);
98
99        tmp_failed = NULL;
100
101        interface_flags = 0;
102        if (eazel_install_get_update (service)) {
103                interface_flags |= INSTALL_UPGRADE;
104        }
105
106        for (iterator = *packages; iterator; iterator = g_list_next (iterator)) {
107                PackageData *pack;
108                int err;
109
110                pack = (PackageData*)iterator->data;
111                if (!eazel_install_get_uninstall (service)) {
112                        g_assert (pack->packsys_struc);
113                        err = rpmtransAddPackage (set,
114                                                  ((Header) pack->packsys_struc),
115                                                  NULL, 
116                                                  NULL,
117                                                  interface_flags, 
118                                                  NULL);
119                        if (err!=0) {
120                                trilobite_debug ("rpmtransAddPackage (..., %s, ...) = %d", pack->name, err);
121                                if (pack->source_package) {
122                                        pack->status = PACKAGE_SOURCE_NOT_SUPPORTED;
123                                } else {
124                                        pack->status = PACKAGE_INVALID;
125                                }
126                                /* We cannot remove the thing immediately from packages, as
127                                   we're iterating it, so add to a tmp list and nuke later */
128                                tmp_failed = g_list_prepend (tmp_failed, pack);
129                        }
130                        /* just flailing around here (robey)
131                        if (pack->soft_depends) {
132                                eazel_install_add_to_rpm_set (service, set, &pack->soft_depends, failed);
133                        }
134                        */
135                } else {
136                        g_assert_not_reached ();
137                }
138        }
139        /* Remove all failed from packages, and add them to failed */
140        if (tmp_failed) {
141                for (iterator = tmp_failed; iterator; iterator = g_list_next (iterator)) {
142                        if (failed) {
143                                (*failed) = g_list_prepend (*failed, iterator->data);
144                        }
145                        (*packages) = g_list_remove (*packages, iterator->data);
146                }
147                g_list_free (tmp_failed);
148        }
149}
150
151/* Given a filename, it find the
152   package that has a package in modifies that
153   provides the given file. */
154
155static int
156eazel_install_package_modifies_provides_compare (PackageData *pack,
157                                                 char *name)
158{
159        GList *ptr = NULL;
160        ptr = g_list_find_custom (pack->modifies, 
161                                  (gpointer)name, 
162                                  (GCompareFunc)eazel_install_package_provides_compare);
163        if (ptr) {
164                trilobite_debug ("package %s-%s-%s caused harm to %s", 
165                                 pack->name, pack->version, pack->minor,
166                                 name);
167                return 0;
168        } 
169/*
170        for (ptr = pack->provides; ptr; ptr = g_list_next (ptr)) {
171                g_message ("%s strcmp %s = %d", name, (char*)ptr->data, g_strcasecmp (name, (char*)ptr->data));
172        }
173        g_message ("package %s blows %d chunks", pack->name, g_list_length (pack->provides));
174*/
175        return -1;
176}
177
178static void
179eazel_install_rpm_create_requirement (EazelInstall *service,
180                                      PackageData *pack,
181                                      PackageData *dep,
182                                      GList **requirements)
183{
184        g_assert (pack && dep);
185
186        /* Check if a previous conflict solve has fixed this conflict. */
187        if (g_list_find_custom (*requirements,
188                                dep,
189                                (GCompareFunc)eazel_install_requirement_dep_compare)) {
190                trilobite_debug ("Already created requirement for %s", dep->name);
191                packagedata_destroy (dep, FALSE);
192                dep = NULL;
193        } else {
194                PackageRequirement *req;
195                req = packagerequirement_new (pack, dep);                               
196                (*requirements) = g_list_prepend (*requirements, req);
197                                /* debug output code */
198                if (dep->name) {
199                        trilobite_debug ("%s requires package %s", pack->name, dep->name);
200                } else {
201                        trilobite_debug ("%s requires file %s", 
202                                         pack->name, 
203                                         (char*)dep->provides->data);
204                }
205        }
206}
207
208
209/* This is the function to do the RPM system dependency check */
210void
211eazel_install_do_rpm_dependency_check (EazelInstall *service,
212                                       GList **packages,
213                                       GList **failedpackages,
214                                       GList **requirements)
215{
216        int iterator;
217        rpmTransactionSet set;
218        int num_conflicts;
219        struct rpmDependencyConflict *conflicts;
220        struct rpmDependencyConflict conflict;
221        rpmdb db;
222
223        trilobite_debug ("eazel_install_do_rpm_dependency_check");
224
225        g_assert (EAZEL_PACKAGE_SYSTEM_RPM3 (service->private->package_system)->private->dbs);
226
227        eazel_package_system_rpm3_open_dbs (EAZEL_PACKAGE_SYSTEM_RPM3 (service->private->package_system));
228        db = (rpmdb)g_hash_table_lookup (EAZEL_PACKAGE_SYSTEM_RPM3 (service->private->package_system)->private->dbs,
229                                         service->private->cur_root);
230        if (!db) {
231                return;
232        }
233
234        set =  rpmtransCreateSet (db, service->private->cur_root);
235        eazel_install_add_to_rpm_set (service, set, packages, failedpackages); 
236
237        /* Reorder the packages as per. deps and do the dep check */
238        rpmdepOrder (set);             
239        rpmdepCheck (set, &conflicts, &num_conflicts);
240        eazel_package_system_rpm3_close_dbs (EAZEL_PACKAGE_SYSTEM_RPM3 (service->private->package_system));
241
242        /* FIXME bugzilla.eazel.com 1512:
243           This piece of code is rpm specific. It has some generic algorithm
244           for doing the dep stuff, but it's rpm entangled */
245
246        for (iterator = 0; iterator < num_conflicts; iterator++) {
247                GList *pack_entry = NULL;
248                PackageData *pack = NULL;
249                PackageData *dep = NULL;
250
251                conflict = conflicts[iterator];
252
253                /* Locate the package that caused the conflict */
254                pack_entry = g_list_find_custom (*packages, 
255                                                 (char*)conflict.byName,
256                                                 (GCompareFunc)eazel_install_package_name_compare);
257
258                /* first time through, only do immediate matches */
259                if (pack_entry == NULL) {
260                        continue;
261                }
262
263                pack = (PackageData*)pack_entry->data;
264                /* Does the conflict look like a file dependency ? */
265                if (*conflict.needsName=='/' || strstr (conflict.needsName, ".so")) {
266                        g_message (_("Processing dep for %s, requires library %s"), 
267                                   pack->name, conflict.needsName);             
268                        dep = packagedata_new ();
269                        dep->provides = g_list_append (dep->provides, g_strdup (conflict.needsName));
270                } else {
271                        dep = packagedata_new_from_rpm_conflict (conflict);
272                        dep->archtype = g_strdup (pack->archtype);
273                        g_message (_("Processing dep for %s, requires package %s"), 
274                                   pack->name, 
275                                   dep->name);
276                }
277
278                eazel_install_rpm_create_requirement (service, pack, dep, requirements);
279        }
280
281        /* now iterate the HARD cases, life sucks! */
282        for (iterator = 0; iterator < num_conflicts; iterator++) {
283                GList *pack_entry = NULL;
284                PackageData *pack = NULL;
285                PackageData *dep = NULL;
286
287                conflict = conflicts[iterator];
288
289                /* Locate the package that caused the conflict */
290                pack_entry = g_list_find_custom (*packages, 
291                                                 (char*)conflict.byName,
292                                                 (GCompareFunc)eazel_install_package_name_compare);
293                if (pack_entry == NULL) {
294                        /* try our brand-new list of required packages, too */
295                        pack_entry = g_list_find_custom (*requirements,
296                                                         (char*)conflict.byName,
297                                                         (GCompareFunc)eazel_install_requirement_dep_name_compare);
298                        if (pack_entry != NULL) {
299                                trilobite_debug (_("package %s is already in requirements, whew!"), conflict.byName);
300                        }
301                }
302                if (pack_entry != NULL) {
303                        continue;
304                }
305
306                /* If we did not find it, we're in a special case conflict */
307                switch (conflict.sense) {
308                case RPMDEP_SENSE_REQUIRES: {                           
309                                /* Possibly the implest case, we're installing package A, which requires
310                                   B that is not installed. */
311                        g_message (_("%s requires %s"), 
312                                   conflict.byName,
313                                   conflict.needsName);
314                        pack_entry = g_list_find_custom (*packages, 
315                                                         (gpointer)conflict.needsName,
316                                                         (GCompareFunc)eazel_install_package_name_compare);
317                        if (pack_entry==NULL) {
318                                /* If pack_entry is null, we're in the worse case, where
319                                   install A causes file f to disappear, and package conflict.byName
320                                   needs f (conflict.needsName). So conflict does not identify which
321                                   package caused the conflict */
322                                trilobite_debug ("pack_entry==NULL, level 2");
323                                /*
324                                   I need to find the package P in "packages" that provides
325                                   conflict.needsName, then fail P marking it's status as
326                                   PACKAGE_BREAKS_DEPENDENCY, then create PackageData C for
327                                   conflict.byName, add to P's depends and mark C's status as
328                                   PACKAGE_DEPENDENCY_FAIL.
329                                   Then then client can rerun the operation with all the C's as
330                                   part of the update
331                                */
332                                pack_entry = g_list_find_custom (*packages, 
333                                                                 (gpointer)conflict.needsName,
334                                                                 (GCompareFunc)eazel_install_package_modifies_provides_compare);
335                                if (pack_entry == NULL) {
336                                        trilobite_debug ("pack_entry==NULL, level 3");
337                                        /* K�e probably already moved it to
338                                           failed packages */
339                                        pack_entry = g_list_find_custom (*failedpackages, 
340                                                                         (gpointer)conflict.needsName,
341                                                                         (GCompareFunc)eazel_install_package_modifies_provides_compare);                                       
342                                        if (pack_entry == NULL) {
343                                                trilobite_debug ("pack_entry==NULL, level 4");
344                                                /* Still k�e're looking for a name... */
345                                                pack_entry = g_list_find_custom (*failedpackages, 
346                                                                                 (gpointer)conflict.needsName,
347                                                                                 (GCompareFunc)eazel_install_package_name_compare);                                     
348                                                if (pack_entry == NULL) {
349                                                        /* Massive debug output before I die.... */
350                                                        int a;
351                                                        GList *ptr;
352                                                        trilobite_debug ("This was certainly unexpected v5!");
353                                                        trilobite_debug ("*********************************");
354                                                        trilobite_debug ("Cannot lookup %s for %s", 
355                                                                         conflict.needsName,
356                                                                         conflict.byName);
357                                                        trilobite_debug ("Cannot lookup %s in *packages",
358                                                                         conflict.needsName);
359                                                        trilobite_debug ("Cannot lookup %s in *failedpackages",
360                                                                         conflict.needsName);
361                                                       
362                                                        trilobite_debug ("packages = 0x%p", packages);
363                                                        trilobite_debug ("*packages = 0x%p", *packages);
364                                                        trilobite_debug ("failedpackages = 0x%p", failedpackages);
365                                                        trilobite_debug ("*failedpackages = 0x%p", *failedpackages);
366                                                       
367                                                        trilobite_debug ("g_list_length (*packages) = %d", g_list_length (*packages));
368                                                        trilobite_debug ("g_list_length (*failedpackages) = %d", g_list_length (*failedpackages));
369                                                        a = 0;
370                                                        for (ptr = *packages; ptr; glist_step (ptr)) {
371                                                                PackageData *p = (PackageData*)ptr->data;
372                                                                a++;
373                                                                trilobite_debug ("(*packages)[%d] = %s-%s-%s",
374                                                                                 a,
375                                                                                 p->name,
376                                                                                 p->version,
377                                                                                 p->minor);
378                                                        }
379                                                        a = 0;
380                                                        for (ptr = *failedpackages; ptr; glist_step (ptr)) {
381                                                                PackageData *p = (PackageData*)ptr->data;
382                                                                a++;
383                                                                trilobite_debug ("(*failedpackages)[%d] = %s-%s-%s",
384                                                                                 a,
385                                                                                 p->name,
386                                                                                 p->version,
387                                                                                 p->minor);
388                                                        }
389                                                       
390                                                       
391                                                        g_assert_not_reached ();
392                                                }
393                                        } 
394                                        /* If we reach this point, the package
395                                           was found in *failedpackages. Otherwise,
396                                           we would have hit the g_assert */
397                                        trilobite_debug ("We don't want to redo failing it");
398                                        pack_entry = NULL;
399                                }
400                        }
401                       
402                        if (pack_entry) {
403                                trilobite_debug ("pack_entry found");
404                                /* Create a packagedata for the dependecy */
405                                dep = packagedata_new_from_rpm_conflict_reversed (conflict);
406                                pack = (PackageData*)(pack_entry->data);
407                                dep->archtype = g_strdup (pack->archtype);
408                                pack->status = PACKAGE_BREAKS_DEPENDENCY;
409                                dep->status = PACKAGE_DEPENDENCY_FAIL;
410                                g_assert (dep!=NULL);
411                        } else {
412                                trilobite_debug ("pack_enty is NULL, continueing");
413                                continue;
414                        }
415                       
416                                /* Here I check to see if I'm breaking the -devel package, if so,
417                                   request it. It does a pretty generic check to see
418                                   if dep is on the form x-z and pack is x[-y] */
419                       
420                        if (eazel_install_check_if_related_package (service, pack, dep)) {
421                                trilobite_debug ("check_if_related_package returned TRUE");
422                                g_free (dep->version);
423                                dep->version = g_strdup (pack->version);
424                        } else {
425                                trilobite_debug ("check_if_related_package returned FALSE");
426                                /* not the devel package, are we in force mode ? */
427                                if (!eazel_install_get_force (service)) {
428                                        /* if not, remove the package */
429                                        packagedata_add_pack_to_breaks (pack, dep);
430                                        if (g_list_find (*failedpackages, pack) == NULL) {
431                                                (*failedpackages) = g_list_prepend (*failedpackages, pack);
432                                        }
433                                        (*packages) = g_list_remove (*packages, pack);
434                                }
435                                continue;
436                        }
437                }
438                break;
439                case RPMDEP_SENSE_CONFLICTS:
440                                /* This should be set if there's a file conflict,
441                                   but I don't think rpm ever does that...
442                                   Because the code below is broken, I've inserted
443                                   a g_assert_not_reached (eskil, Sept 2000)
444                                */
445                        g_assert_not_reached ();
446                                /* If we end here, it's a conflict is going to break something */
447                        g_warning (_("Package %s conflicts with %s-%s"), 
448                                   conflict.byName, conflict.needsName, 
449                                   conflict.needsVersion);
450                        if (g_list_find (*failedpackages, pack) == NULL) {
451                                (*failedpackages) = g_list_prepend (*failedpackages, pack);
452                        }
453                        (*packages) = g_list_remove (*packages, pack);
454                        continue;
455                        break;
456                }
457               
458                eazel_install_rpm_create_requirement (service, pack, dep, requirements);
459        }
460
461        rpmdepFreeConflicts (conflicts, num_conflicts);
462        rpmtransFree (set);
463        trilobite_debug ("eazel_install_do_rpm_dependency_check ended with %d fails and %d requirements", 
464                         g_list_length (*failedpackages),
465                         g_list_length (*requirements));
466}
Note: See TracBrowser for help on using the browser.