Implemented 3rd party package policy to no break SSU.
[hildon-application-manager:mainline.git] / src / apt-worker.cc
1 /*
2  * This file is part of the hildon-application-manager.
3  *
4  * Parts of this file are derived from apt.  Apt is copyright 1997,
5  * 1998, 1999 Jason Gunthorpe and others.
6  *
7  * Copyright (C) 2005, 2006, 2007, 2008 Nokia Corporation.  All Rights reserved.
8  *
9  * Contact: Marius Vollmer <marius.vollmer@nokia.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License version
13  * 2 as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  *
25  */
26
27 /* This is the process that runs as root and does all the work.
28
29    It is started from a separate program (as opposed to being forked
30    directly from the GUI process) since that allows us to use sudo for
31    starting it.
32
33    This process communicates with the GUI process via some named pipes
34    that are created by that process.  You can't really use it from the
35    command line.
36
37    It will output stuff to stdin and stderr, which the GUI process is
38    supposed to catch and put into its log.
39
40    The program tries hard not to exit prematurely.  Once the
41    connection between the GUI process and this process has been
42    established, the apt-worker is supposed to stick around until that
43    connection is broken, even if it has to fail every request send to
44    it.  This allows the user to try and fix the system after something
45    went wrong, although the options are limited, of course.  The best
46    example is a corrupted /etc/apt/sources.list: even tho you can't do
47    anything related to packages, you still need the apt-worker to
48    correct /etc/apt/sources.list itself in the UI.
49 */
50
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <unistd.h>
54 #include <assert.h>
55 #include <stdarg.h>
56 #include <sys/ioctl.h>
57 #include <sys/stat.h>
58 #include <sys/statvfs.h>
59 #include <sys/types.h>
60 #include <sys/fcntl.h>
61 #include <errno.h>
62 #include <dirent.h>
63 #include <signal.h>
64 #include <ftw.h>
65
66 #include <fstream>
67
68 #include <apt-pkg/init.h>
69 #include <apt-pkg/error.h>
70 #include <apt-pkg/tagfile.h>
71 #include <apt-pkg/pkgcache.h>
72 #include <apt-pkg/pkgcachegen.h>
73 #include <apt-pkg/sourcelist.h>
74 #include <apt-pkg/acquire.h>
75 #include <apt-pkg/acquire-item.h>
76 #include <apt-pkg/cachefile.h>
77 #include <apt-pkg/strutl.h>
78 #include <apt-pkg/sptr.h>
79 #include <apt-pkg/packagemanager.h>
80 #include <apt-pkg/deblistparser.h>
81 #include <apt-pkg/debversion.h>
82 #include <apt-pkg/dpkgpm.h>
83 #include <apt-pkg/debsystem.h>
84 #include <apt-pkg/orderlist.h>
85 #include <apt-pkg/algorithms.h>
86 #include <apt-pkg/metaindex.h>
87 #include <apt-pkg/debmetaindex.h>
88 #include <apt-pkg/policy.h>
89 #include <apt-pkg/md5.h>
90 #include <apt-pkg/sha1.h>
91 #include <apt-pkg/sha256.h>
92
93 #include <glib/glist.h>
94 #include <glib/gstring.h>
95 #include <glib/gstrfuncs.h>
96 #include <glib/gmem.h>
97 #include <glib/gfileutils.h>
98 #include <glib/gslist.h>
99 #include <glib/gkeyfile.h>
100
101 #include "apt-worker-proto.h"
102 #include "confutils.h"
103
104 #include "update-notifier-conf.h"
105
106 using namespace std;
107
108 static void save_operation_record (const char *package,
109                                    const char *download_root);
110 static void erase_operation_record ();
111 static xexp *read_operation_record ();
112
113 /* Table of contents.
114  
115    COMPILE-TIME CONFIGURATION
116    
117    RUN-TIME CONFIGURATION
118
119    GENERAL UTILITIES
120
121    COMMUNICATING WITH THE FRONTEND
122
123    STARTUP AND COMMAND DISPATCHER
124
125    CACHE HANDLING
126 */
127
128
129 /** COMPILE-TIME CONFIGURATION
130  */
131
132 /* Defining this to non-zero will also recognize packages in the
133    "maemo" section as user packages.  There are still packages
134    floating around that follow this old rule.
135 */
136 #define ENABLE_OLD_MAEMO_SECTION_TEST 1
137
138 /* Requests up to this size are put into a stack allocated buffer.
139  */
140 #define FIXED_REQUEST_BUF_SIZE 4096
141
142 /* The location where we keep our lock.
143  */
144 #define APT_WORKER_LOCK "/var/lib/hildon-application-manager/apt-worker-lock"
145
146 /* Temporary catalogues and temporary sources.list */
147 #define TEMP_CATALOGUE_CONF "/var/lib/hildon-application-manager/catalogues.temp"
148 #define TEMP_APT_SOURCE_LIST "/etc/apt/sources.list.d/hildon-application-manager-temp.list"
149
150 /* APT CACHE ARCHIVES DIRECTORIES */
151 #define DEFAULT_DIR_CACHE_ARCHIVES "archives/"
152 #define ALT_DIR_CACHE_ARCHIVES ".apt-archive-cache/"
153
154 /* Files related to the 'check for updates' process */
155 #define FAILED_CATALOGUES_FILE "/var/lib/hildon-application-manager/failed-catalogues"
156
157 /* Domain names associated with "OS" and "Nokia" updates */
158 #define OS_UPDATES_DOMAIN_NAME "nokia-system"
159 #define NOKIA_UPDATES_DOMAIN_NAME "nokia-certified"
160
161 /* Where we keep a journal of the current operation
162  */
163 #define CURRENT_OPERATION_FILE "/var/lib/hildon-application-manager/current-operation"
164
165 /* You know what this means.
166  */
167 /*#define DEBUG*/
168 /*#define DEBUG_COMMANDS*/
169
170 #ifdef DEBUG
171 #define DBG log_stderr
172 #else
173 #define DBG(...)
174 #endif
175
176 /** RUN-TIME CONFIGURATION
177  */
178
179 /* Setting this to true will break the lock of the dpkg status
180    database if necessary.
181 */
182 bool flag_break_locks = false;
183
184 /* Setting this to true will not ignore package versions from a wrong
185    domain.
186  */
187 bool flag_allow_wrong_domains = false;
188
189 /* Setting this to true will use the normal apt-get algorithms for
190    installing/removing packages instead of our home-grown ones.
191 */
192 bool flag_use_apt_algorithms = false;
193
194 /* Setting this to false will not use MMC to save the packages when
195    downloading them.
196 */
197 bool flag_download_packages_to_mmc = false;
198
199 /** GENERAL UTILITIES
200  */
201
202 void
203 log_stderr (const char *fmt, ...)
204 {
205   va_list args;
206   va_start (args, fmt);
207   fprintf (stderr, "apt-worker: ");
208   vfprintf (stderr, fmt, args);
209   va_end (args);
210   fprintf (stderr, "\n");
211 }
212
213 /** APT WORKER MULTI STATE MANAGEMENT
214  */
215
216 /* Inside this process, domains are identified with small integers.
217  */
218
219 typedef signed char domain_t;
220
221 struct domain_info {
222   const char *name;
223   xexp *conf;
224   int trust_level;
225   bool is_certified;
226 };
227
228 xexp *domain_conf = NULL;
229 domain_info *domains = NULL;
230 int domains_number = 0;
231 time_t domains_last_modified = -1;
232
233 #define DOMAIN_INVALID  -1
234 #define DOMAIN_UNSIGNED  0
235 #define DOMAIN_SIGNED    1 
236
237 #define DOMAIN_DEFAULT DOMAIN_UNSIGNED
238
239 static time_t
240 file_last_modified (const char *file_name)
241 {
242   struct stat buf;
243
244   if (stat (file_name, &buf) == -1)
245     {
246       perror ("error retriving file info");
247       return -1;
248     }
249
250   return buf.st_mtime;
251 }
252
253 static void
254 read_domain_conf ()
255 {
256   delete[] domains;
257   xexp_free (domain_conf);
258
259   domain_conf = read_domains ();
260
261   int n_domains = 2;
262   if (domain_conf)
263     n_domains += xexp_length (domain_conf);
264
265   domains = new domain_info[n_domains];
266
267   /* Setup the two implicit domains.
268    */
269   domains[0].name = "unsigned";
270   domains[0].conf = NULL;
271   domains[0].trust_level = 0;
272   domains[0].is_certified = false;
273     
274   domains[1].name = "signed";
275   domains[1].conf = NULL;
276   domains[1].trust_level = 1;
277   domains[1].is_certified = false;
278
279   int i = 2;
280   if (domain_conf)
281     {
282       for (xexp *d = xexp_first (domain_conf); d; d = xexp_rest (d))
283         {
284           if (!xexp_is (d, "domain"))
285             continue;
286
287           domains[i].name = xexp_aref_text (d, "name");
288           if (domains[i].name == NULL)
289             continue;
290
291           domains[i].trust_level = xexp_aref_int (d, "trust-level", 2);
292           domains[i].is_certified = xexp_aref_bool (d, "certified");
293           domains[i].conf = d;
294
295           i += 1;
296         }
297     }
298
299   /* Update domains number and last modified timestamp */
300   domains_number = i;
301   domains_last_modified = file_last_modified (PACKAGE_DOMAINS);
302 }
303
304 static domain_t
305 find_domain_by_tag (const char *tag, const char *val)
306 {
307   for (int i = 0; i < domains_number; i++)
308     {
309       if (domains[i].conf == NULL)
310         continue;
311
312       for (xexp *x = xexp_aref (domains[i].conf, tag);
313            x;
314            x = xexp_aref_rest (x, tag))
315         {
316           if (xexp_is_text (x) && g_str_has_suffix (xexp_text (x), val))
317             return i;
318         }
319     }
320
321   return DOMAIN_SIGNED;
322 }
323
324 static domain_t
325 find_domain_by_key (const char *key)
326 {
327   return find_domain_by_tag ("key", key);
328 }
329
330 static domain_t
331 find_domain_by_uri (const char *uri)
332 {
333   return find_domain_by_tag ("uri", uri);
334 }
335
336 class myCacheFile;
337
338 /* This class implements a global static cache managing for
339  *  apt-worker. */
340 class AptWorkerCache
341 {
342 public:
343   AptWorkerCache ();
344   static void Initialize ();
345   static AptWorkerCache * GetCurrent ();
346   
347   bool init_cache_after_request;  
348   myCacheFile *cache;
349   pkgDepCache::ActionGroup *action_group;
350   static AptWorkerCache *current;
351   static bool global_initialized;
352 };
353
354 AptWorkerCache *AptWorkerCache::current = 0;
355
356 bool AptWorkerCache::global_initialized = false;
357
358 AptWorkerCache::AptWorkerCache ()
359   : init_cache_after_request (false), cache (0)
360 {
361 }
362
363 AptWorkerCache *
364 AptWorkerCache::GetCurrent (void)
365 {
366   return current;
367 }  
368
369 /* Initialization of apt worker cache. It initializes the
370  * APT subsystem, and then gets the current instance. */
371 void
372 AptWorkerCache::Initialize (void)
373 {
374   if (!global_initialized)
375     {
376       if (pkgInitConfig (*_config) == false ||
377           pkgInitSystem (*_config, _system) == false)
378         {
379           _error->DumpErrors ();
380           return;
381         }
382
383       _config->Set ("DPkg::Options::", "--force-confold");
384       _config->Set ("Dir::Log", "var/log");
385       _config->Set ("Dir::Log::Terminal", "");
386       global_initialized = true;
387     }
388
389   current = new AptWorkerCache;
390 }
391   
392 /* This struct describes some status flags for specific packages.
393  * myCacheFile includes an array of these, with an entry per
394  * package.
395  */
396 typedef struct extra_info_struct
397 {
398   bool autoinst : 1;
399   bool related : 1;
400   bool soft : 1;
401   domain_t cur_domain, new_domain;
402 };
403
404 class myPolicy : public pkgPolicy {
405
406 protected:
407   myCacheFile *my_cache_file;
408   int *pf_domain;
409
410 public:
411   myPolicy (pkgCache *Owner, myCacheFile *cache_file)
412     : pkgPolicy (Owner), my_cache_file (cache_file)
413   {
414     pf_domain = new int[Owner->Head().PackageFileCount];
415   }
416
417   void InitDomains ();
418
419   virtual pkgCache::VerIterator GetCandidateVer(pkgCache::PkgIterator Pkg);
420 };
421
422 class myCacheFile : public pkgCacheFile {
423
424 public:
425   bool Open (OpProgress &Progress, bool WithLock = true);
426
427   void load_extra_info ();
428   void save_extra_info ();
429
430   extra_info_struct *extra_info;
431
432   myCacheFile ()
433   {
434     extra_info = NULL;
435   }
436
437   ~myCacheFile ()
438   {
439     delete[] extra_info;
440   }
441 };
442
443 static void set_sources_for_get_domain (pkgSourceList *sources);
444 static int get_domain (pkgIndexFile*);
445
446 void
447 myPolicy::InitDomains ()
448 {
449   for (pkgCache::PkgFileIterator I = Cache->FileBegin();
450        I != Cache->FileEnd(); I++)
451     pf_domain[I->ID] = DOMAIN_UNSIGNED;
452
453   pkgSourceList List;
454   if (!List.ReadMainList ())
455     {
456       _error->DumpErrors();
457       return;
458     }
459
460   set_sources_for_get_domain (&List);
461
462   for (pkgCache::PkgFileIterator I = Cache->FileBegin();
463        I != Cache->FileEnd(); I++)
464     {
465       // Locate the associated index files so we can find its domain
466       pkgIndexFile *Indx;
467       if (List.FindIndex(I,Indx) || _system->FindIndex(I,Indx))
468         {
469           pf_domain[I->ID] = get_domain (Indx);
470           DBG ("%s: %s", Indx->Describe(true).c_str(),
471                domains[pf_domain[I->ID]].name);
472         }
473     }
474   
475   set_sources_for_get_domain (NULL);
476 }
477
478 static bool domain_dominates_or_is_equal (int a, int b);
479
480 pkgCache::VerIterator 
481 myPolicy::GetCandidateVer (pkgCache::PkgIterator Pkg)
482 {
483   // Look for a package pin and evaluate it.
484   signed Max = GetPriority(Pkg);
485   pkgCache::VerIterator Pref = GetMatch(Pkg);
486   
487   /* Falling through to the default version.. Setting Max to zero
488      effectively excludes everything <= 0 which are the non-automatic
489      priorities.. The status file is given a prio of 100 which will exclude
490      not-automatic sources, except in a single shot not-installed mode.
491      The second pseduo-status file is at prio 1000, above which will permit
492      the user to force-downgrade things.
493      
494      The user pin is subject to the same priority rules as default 
495      selections. Thus there are two ways to create a pin - a pin that
496      tracks the default when the default is taken away, and a permanent
497      pin that stays at that setting.
498   */
499   for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; Ver++)
500     {
501       for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false;
502            VF++)
503         {
504           /* If this is the status file, and the current version is not the
505              version in the status file (ie it is not installed, or somesuch)
506              then it is not a candidate for installation, ever. This weeds
507              out bogus entries that may be due to config-file states, or
508              other. */
509           if ((VF.File()->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource &&
510               Pkg.CurrentVer() != Ver)
511             continue;
512
513           /* If requested, skip versions from the wrong domain, but
514              only for sources.
515            */
516
517           if (!flag_allow_wrong_domains
518               && ((VF.File()->Flags & pkgCache::Flag::NotSource)
519                   != pkgCache::Flag::NotSource))
520             {
521               if (!domain_dominates_or_is_equal
522                   (pf_domain[VF.File()->ID],
523                    my_cache_file->extra_info[Pkg->ID].cur_domain))
524                 {
525                   log_stderr ("Ignoring version from wrong domain: %s %s",
526                               Pkg.Name(), Ver.VerStr());
527                   log_stderr ("  %s", VF.File().FileName());
528                   continue;
529                 }
530             }
531           
532           signed Prio = PFPriority[VF.File()->ID];
533           if (Prio > Max)
534             {
535               Pref = Ver;
536               Max = Prio;
537             }    
538         }      
539       
540       if (Pkg.CurrentVer() == Ver && Max < 1000)
541         {
542           /* Elevate our current selection (or the status file itself)
543              to the Pseudo-status priority. */
544           if (Pref.end() == true)
545             Pref = Ver;
546           Max = 1000;
547           
548           // Fast path optimize.
549           if (StatusOverride == false)
550             break;
551         }       
552     }
553   return Pref;
554 }
555
556 bool
557 myCacheFile::Open (OpProgress &Progress, bool WithLock)
558 {
559   if (BuildCaches(Progress,WithLock) == false)
560     return false;
561   
562   // The policy engine
563   myPolicy *pol = new myPolicy (Cache, this);
564   Policy = pol;
565   if (_error->PendingError() == true)
566     return false;
567   if (ReadPinFile(*Policy) == false)
568     return false;
569   
570   pol->InitDomains ();
571   
572   load_extra_info ();
573
574   // Create the dependency cache
575   DCache = new pkgDepCache(Cache,Policy);
576   if (_error->PendingError() == true)
577     return false;
578   
579   DCache->Init(&Progress);
580   Progress.Done();
581   if (_error->PendingError() == true)
582     return false;
583   
584   return true;
585 }
586
587 /* Save the 'extra_info' of the cache.  We first make a copy of the
588    Auto flags in our own extra_info storage so that CACHE_RESET
589    will reset the Auto flags to the state last saved with this
590    function.
591 */
592
593 void
594 myCacheFile::save_extra_info ()
595 {
596   if (mkdir ("/var/lib/hildon-application-manager", 0777) < 0
597       && errno != EEXIST)
598     {
599       log_stderr ("/var/lib/hildon-application-manager: %m");
600       return;
601     }
602
603   FILE *f = fopen ("/var/lib/hildon-application-manager/autoinst", "w");
604   if (f)
605     {
606       pkgDepCache &cache = *DCache;
607
608       for (pkgCache::PkgIterator pkg = cache.PkgBegin(); !pkg.end (); pkg++)
609         {
610           if (cache[pkg].Flags & pkgCache::Flag::Auto)
611             {
612               extra_info[pkg->ID].autoinst = true;
613               fprintf (f, "%s\n", pkg.Name ());
614             }
615           else
616             extra_info[pkg->ID].autoinst = false;
617         }
618       fflush (f);
619       fsync (fileno (f));
620       fclose (f);
621     }
622
623   for (domain_t i = 0; i < domains_number; i++)
624     {
625       char *name =
626         g_strdup_printf ("/var/lib/hildon-application-manager/domain.%s",
627                          domains[i].name);
628       
629       FILE *f = fopen (name, "w");
630       if (f)
631         {
632           pkgDepCache &cache = *DCache;
633
634           for (pkgCache::PkgIterator pkg = cache.PkgBegin();
635                !pkg.end (); pkg++)
636             {
637               if (extra_info[pkg->ID].cur_domain == i)
638                 fprintf (f, "%s\n", pkg.Name ());
639             }
640           fflush (f);
641           fsync (fileno (f));
642           fclose (f);
643         }
644     }
645 }
646
647 /* Load the 'extra_info'.  You need to call CACHE_RESET to
648    transfer the auto flag into the actual cache.  */
649
650 void
651 myCacheFile::load_extra_info ()
652 {
653   pkgCache &cache = *Cache;
654
655   int package_count = cache.Head().PackageCount;
656
657   extra_info = new extra_info_struct[package_count];
658
659   for (int i = 0; i < package_count; i++)
660     {
661       extra_info[i].autoinst = false;
662       extra_info[i].cur_domain = DOMAIN_DEFAULT;
663     }
664
665   FILE *f = fopen ("/var/lib/hildon-application-manager/autoinst", "r");
666   if (f)
667     {
668       char *line = NULL;
669       size_t len = 0;
670       ssize_t n;
671
672       while ((n = getline (&line, &len, f)) != -1)
673         {
674           if (n > 0 && line[n-1] == '\n')
675             line[n-1] = '\0';
676
677           pkgCache::PkgIterator pkg = cache.FindPkg (line);
678           if (!pkg.end ())
679             {
680               DBG ("auto: %s", pkg.Name ());
681               extra_info[pkg->ID].autoinst = true;
682             }
683         }
684
685       free (line);
686       fclose (f);
687     }
688
689   for (domain_t i = 0; i < domains_number; i++)
690     {
691       char *name =
692         g_strdup_printf ("/var/lib/hildon-application-manager/domain.%s",
693                          domains[i].name);
694
695       FILE *f = fopen (name, "r");
696       if (f)
697         {
698           char *line = NULL;
699           size_t len = 0;
700           ssize_t n;
701
702           while ((n = getline (&line, &len, f)) != -1)
703             {
704               if (n > 0 && line[n-1] == '\n')
705                 line[n-1] = '\0';
706
707               pkgCache::PkgIterator pkg = cache.FindPkg (line);
708               if (!pkg.end ())
709                 {
710                   // DBG ("%s: %s (%d)", domains[i].name, pkg.Name (), pkg->ID);
711                   extra_info[pkg->ID].cur_domain = i;
712                 }
713             }
714
715           free (line);
716           fclose (f);
717         }
718
719       g_free (name);
720     }
721 }
722
723 /* ALLOC_BUF and FREE_BUF can be used to manage a temporary buffer of
724    arbitrary size without having to allocate memory from the heap when
725    the buffer is small.
726    
727    The way to use them is to allocate a buffer of 'normal' but fixed
728    size statically or on the stack and the use ALLOC_BUF when the
729    actual size of the needed buffer is known.  If the actual size is
730    small enough, ALLOC_BUF will use the fixed size buffer, otherwise
731    it will allocate a new one.  FREE_BUF will free that buffer.
732 */
733
734 /* Return a pointer to LEN bytes of free storage.  When LEN is less
735    than or equal to FIXED_BUF_LEN return FIXED_BUF, otherwise a newly
736    allocated block of memory is returned.  ALLOC_BUF never return
737    NULL.
738 */
739 char *
740 alloc_buf (int len, char *fixed_buf, int fixed_buf_len)
741 {
742   if (len <= fixed_buf_len)
743     return fixed_buf;
744   else
745     return new char[len];
746 }
747
748 /* Free the block of memory pointed to by BUF if it is different from
749    FIXED_BUF.
750 */
751 void
752 free_buf (char *buf, char *fixed_buf)
753 {
754   if (buf != fixed_buf)
755     delete[] buf;
756 }
757
758 /* Open FILENAME with FLAGS, or die.
759  */
760 static int
761 must_open (char *filename, int flags)
762 {
763   int fd = open (filename, flags);
764   if (fd < 0)
765     {
766       perror (filename);
767       exit (1);
768     }
769   return fd;
770 }
771
772 static void
773 must_set_flags (int fd, int flags)
774 {
775   if (fcntl (fd, F_SETFL, flags) < 0)
776     {
777       perror ("apt-worker fcntl");
778       exit (1);
779     }
780 }
781
782 static void
783 block_for_read (int fd)
784 {
785   fd_set set;
786   FD_ZERO (&set);
787   FD_SET (fd, &set);
788
789   if (select (fd+1, &set, NULL, NULL, NULL) < 0)
790     {
791       perror ("apt-worker select");
792       exit (1);
793     }
794 }
795
796 static int
797 read_byte (int fd)
798 {
799   unsigned char byte;
800   if (read (fd, &byte, 1) == 1)
801     return byte;
802   return -1;
803 }
804
805 /* DRAIN_FD reads all bytes from FD that are available.
806 */
807 static void
808 drain_fd (int fd)
809 {
810   while (read_byte (fd) >= 0)
811     ;
812 }
813
814 /* Get a lock as with GetLock from libapt-pkg, breaking it if needed
815    and allowed by flag_break_locks.
816
817    We do this so that the users can not lock themselves out.  We break
818    locks instead of not locking since noisily breaking a lock is
819    better than silently corrupting stuff.
820  */
821 int
822 ForceLock (string File, bool Errors = true)
823 {
824   int lock_fd = GetLock (File, false);
825   if (lock_fd >= 0)
826     return lock_fd;
827
828   if (flag_break_locks)
829     {
830       int res = unlink (File.c_str ());
831       if (res < 0 && errno != ENOENT)
832         log_stderr ("Can't remove %s: %m", File.c_str ());
833       else if (res == 0)
834         log_stderr ("Forcing %s", File.c_str ());
835     }
836
837   return GetLock (File, Errors);
838 }
839
840
841 /** COMMUNICATING WITH THE FRONTEND.
842  
843    The communication with the frontend happens over four
844    unidirectional fifos: requests are read from INPUT_FD and responses
845    are sent back via OUTPUT_FD.  No new request is read until the
846    response to the current one has been completely sent.
847
848    The data read from INPUT_FD must follow the request format
849    specified in <apt-worker-proto.h>.  The data written to OUTPUT_FD
850    follows the response format specified there.
851
852    The CANCEL_FD is polled periodically and when something is
853    available to be read, the current operation is aborted.  There is
854    currently no meaning defined for the actual bytes that are sent,
855    the mere arrival of a byte triggers the abort.
856
857    When using the libapt-pkg PackageManager, it is configured in such
858    a way that it sends it "pmstatus:" message lines to STATUS_FD.
859    Other asynchronous status reports are sent as spontaneous
860    APTCMD_STATUS responses via OUTPUT_FD.  'Spontaneous' should mean
861    that no request is required to receive APTCMD_STATUS responses.  In
862    fact, APTCMD_STATUS requests are treated as an error by the
863    apt-worker.
864
865    Logging and debug output, and output from dpkg and the maintainer
866    scripts appears normally on stdout and stderr of the apt-worker
867    process.
868 */
869
870 int input_fd, output_fd, status_fd, cancel_fd;
871
872 /* MUST_READ and MUST_WRITE read and write blocks of raw bytes from
873    INPUT_FD and to OUTPUT_FD.  If they return, they have succeeded and
874    read or written the whole block.
875 */
876
877 void
878 must_read (void *buf, size_t n)
879 {
880   int r;
881
882   while (n > 0)
883     {
884       r = read (input_fd, buf, n);
885       if (r < 0)
886         {
887           perror ("apt-worker read");
888           exit (1);
889         }
890       else if (r == 0)
891         {
892           DBG ("exiting");
893           exit (0);
894         }
895       n -= r;
896       buf = ((char *)buf) + r;
897     }
898 }
899
900 static void
901 must_write (void *buf, ssize_t n)
902 {
903   if (n > 0 && write (output_fd, buf, n) != n)
904     {
905       perror ("apt-worker write");
906       exit (1);
907     }
908 }
909
910 /* This function sends a response on OUTPUT_FD with the given CMD and
911    SEQ.  It either succeeds or does not return.
912 */
913 void
914 send_response_raw (int cmd, int seq, void *response, size_t len)
915 {
916   apt_response_header res = { cmd, seq, len };
917   must_write (&res, sizeof (res));
918   must_write (response, len);
919 }
920
921 /* Fabricate and send a APTCMD_STATUS response.  Parameters OP,
922    ALREADY, and TOTAL are as specified in apt-worker-proto.h.
923
924    A status response is only sent when there is enough change since
925    the last time.  The following counts as 'enough': ALREADY has
926    decreased, it has increased by more than MIN_CHANGE, it is equal to
927    -1, LAST_TOTAL has changed, or OP has changed.
928 */
929
930 void
931 send_status (int op, int already, int total, int min_change)
932 {
933
934   static apt_proto_encoder status_response;
935   static int last_op;
936   static int last_already;
937   static int last_total;
938
939   if (already == -1 
940       || already < last_already 
941       || already >= last_already + min_change
942       || total != last_total
943       || op != last_op)
944     {
945       last_already = already;
946       last_total = total;
947       last_op = op;
948       
949       status_response.reset ();
950       status_response.encode_int (op);
951       status_response.encode_int (already);
952       status_response.encode_int (total);
953       send_response_raw (APTCMD_STATUS, -1, 
954                          status_response.get_buf (),
955                          status_response.get_len ());
956     }
957 }
958
959
960 /** STARTUP AND COMMAND DISPATCHER.
961  */
962
963 /* Since the apt-worker only works on a single command at a time, we
964    use two global encoder and decoder engines that manage the
965    parameters of the request and the result values of the response.
966
967    Handlers of specific commands will read the parameters from REQUEST
968    and put the results into RESPONSE.  The command dispatcher will
969    prepare REQUEST before calling the command handler and ship out
970    RESPONSE after it returned.
971 */
972 apt_proto_decoder request;
973 apt_proto_encoder response;
974
975 void cmd_get_package_list ();
976 void cmd_get_package_info ();
977 void cmd_get_package_details ();
978 int cmd_check_updates (bool with_status = true);
979 void cmd_get_catalogues ();
980 void cmd_set_catalogues ();
981 void cmd_add_temp_catalogues ();
982 void cmd_rm_temp_catalogues ();
983 void cmd_install_check ();
984 void cmd_download_package ();
985 void cmd_install_package ();
986 void cmd_remove_check ();
987 void cmd_remove_package ();
988 void cmd_clean ();
989 void cmd_get_file_details ();
990 void cmd_install_file ();
991 void cmd_save_backup_data ();
992 void cmd_get_system_update_packages ();
993 void cmd_reboot ();
994 void cmd_set_options ();
995 void cmd_set_env ();
996
997 int cmdline_check_updates (char **argv);
998 int cmdline_rescue (char **argv);
999
1000 /** MANAGEMENT FOR FAILED CATALOGUES LOG FILE
1001  */
1002
1003 /* Since it's needed to save the full report (including errors) after
1004    any refresh of the catalogues list, four functions were implemented
1005    to take care of the writting/reading to/from disk process.
1006 */
1007
1008 static void save_failed_catalogues (xexp *catalogues);
1009 static xexp *load_failed_catalogues ();
1010 static void clean_failed_catalogues ();
1011 static void clean_temp_catalogues ();
1012 static xexp *merge_catalogues_with_errors (xexp *catalogues);
1013
1014 /** MANAGEMENT OF FILE WITH INFO ABOUT AVAILABLE UPDATES */
1015
1016 static void write_available_updates_file ();
1017
1018 /** MAPPING FUNCTION TO FILTER ERROR DETAILS
1019     IN CATALOGUES CONFIGURATION FILE
1020 */
1021 static xexp *map_catalogue_error_details (xexp *x);
1022
1023
1024 /* Commands can request the package cache to be refreshed by calling
1025    NEED_CACHE_INIT before they return.  The cache will then be
1026    reconstructed after sending the response and before starting to
1027    handle the next command.  In this way, the cache reconstruction
1028    happens in the background.
1029
1030    XXX - However, APTCMD_STATUS messages are still being sent when the
1031          cache is reconstructed in the background and the UI has some
1032          ugly logic to deal with that.
1033 */
1034
1035 void cache_init (bool with_status = true);
1036
1037 void
1038 need_cache_init ()
1039 {
1040   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
1041   awc->init_cache_after_request = true;
1042 }
1043
1044 #ifdef DEBUG_COMMANDS
1045 static const char *cmd_names[] = {
1046   "NOOP",
1047   "STATUS",
1048   "GET_PACKAGE_LIST",
1049   "GET_PACKAGE_INFO",
1050   "GET_PACKAGE_DETAILS",
1051   "CHECK_UPDATES",
1052   "GET_CATALOGUES",
1053   "SET_CATALOGUES",
1054   "ADD_TEMP_CATALOGUES",
1055   "RM_TEMP_CATALOGUES",
1056   "INSTALL_CHECK",
1057   "INSTALL_PACKAGE",
1058   "REMOVE_CHECK",
1059   "REMOVE_PACKAGE",
1060   "GET_FILE_DETAILS",
1061   "INSTALL_FILE",
1062   "CLEAN",
1063   "SAVE_BACKUP_DATA",
1064   "GET_SYSTEM_UPDATE_PACKAGES",
1065   "FLASH_AND_REBOOT",
1066   "SET_OPTIONS",
1067   "SET_ENV"
1068 };
1069 #endif
1070
1071 void
1072 handle_request ()
1073 {
1074   apt_request_header req;
1075   char stack_reqbuf[FIXED_REQUEST_BUF_SIZE];
1076   char *reqbuf;
1077   AptWorkerCache * awc = 0;
1078   time_t last_modified = -1;
1079
1080   must_read (&req, sizeof (req));
1081
1082 #ifdef DEBUG_COMMANDS
1083   DBG ("got req %s/%d/%d", cmd_names[req.cmd], req.seq, req.len);
1084 #endif
1085
1086   reqbuf = alloc_buf (req.len, stack_reqbuf, FIXED_REQUEST_BUF_SIZE);
1087   must_read (reqbuf, req.len);
1088
1089   drain_fd (cancel_fd);
1090
1091   request.reset (reqbuf, req.len);
1092   response.reset ();
1093
1094   awc = AptWorkerCache::GetCurrent ();
1095   awc->init_cache_after_request = false; // let's reset it now
1096
1097   /* Re-read domains conf file if modified */
1098   last_modified = file_last_modified (PACKAGE_DOMAINS);
1099   if (last_modified != domains_last_modified)
1100     read_domain_conf ();
1101
1102   switch (req.cmd)
1103     {
1104
1105     case APTCMD_NOOP:
1106       // Nothing to do.
1107       break;
1108
1109     case APTCMD_GET_PACKAGE_LIST:
1110       cmd_get_package_list ();
1111       break;
1112
1113     case APTCMD_GET_PACKAGE_INFO:
1114       cmd_get_package_info ();
1115       break;
1116
1117     case APTCMD_GET_PACKAGE_DETAILS:
1118       cmd_get_package_details ();
1119       break;
1120
1121     case APTCMD_CHECK_UPDATES:
1122       cmd_check_updates ();
1123       break;
1124
1125     case APTCMD_GET_CATALOGUES:
1126       cmd_get_catalogues ();
1127       break;
1128
1129     case APTCMD_SET_CATALOGUES:
1130       cmd_set_catalogues ();
1131       break;
1132
1133     case APTCMD_ADD_TEMP_CATALOGUES:
1134       cmd_add_temp_catalogues ();
1135       break;
1136
1137     case APTCMD_RM_TEMP_CATALOGUES:
1138       cmd_rm_temp_catalogues ();
1139       break;
1140
1141     case APTCMD_INSTALL_CHECK:
1142       cmd_install_check ();
1143       break;
1144
1145     case APTCMD_DOWNLOAD_PACKAGE:
1146       cmd_download_package ();
1147       break;
1148
1149     case APTCMD_INSTALL_PACKAGE:
1150       cmd_install_package ();
1151       break;
1152
1153     case APTCMD_REMOVE_CHECK:
1154       cmd_remove_check ();
1155       break;
1156
1157     case APTCMD_REMOVE_PACKAGE:
1158       cmd_remove_package ();
1159       break;
1160
1161     case APTCMD_CLEAN:
1162       cmd_clean ();
1163       break;
1164
1165     case APTCMD_GET_FILE_DETAILS:
1166       cmd_get_file_details ();
1167       break;
1168
1169     case APTCMD_INSTALL_FILE:
1170       cmd_install_file ();
1171       break;
1172
1173     case APTCMD_SAVE_BACKUP_DATA:
1174       cmd_save_backup_data ();
1175       break;
1176
1177     case APTCMD_GET_SYSTEM_UPDATE_PACKAGES:
1178       cmd_get_system_update_packages ();
1179       break;
1180
1181     case APTCMD_REBOOT:
1182       cmd_reboot ();
1183       break;
1184
1185     case APTCMD_SET_OPTIONS:
1186       cmd_set_options ();
1187       break;
1188
1189     case APTCMD_SET_ENV:
1190       cmd_set_env ();
1191       break;
1192
1193     default:
1194       log_stderr ("unrecognized request: %d", req.cmd);
1195       break;
1196     }
1197
1198   _error->DumpErrors ();
1199
1200   send_response_raw (req.cmd, req.seq,
1201                      response.get_buf (), response.get_len ());
1202
1203 #ifdef DEBUG_COMMANDS
1204   DBG ("sent resp %s/%d/%d",
1205        cmd_names[req.cmd], req.seq, response.get_len ());
1206 #endif
1207
1208   free_buf (reqbuf, stack_reqbuf);
1209
1210   if (awc->init_cache_after_request)
1211     {
1212       cache_init (false);
1213       _error->DumpErrors ();
1214     }
1215 }
1216
1217 static int index_trust_level_for_package (pkgIndexFile *index,
1218                                           const pkgCache::VerIterator &ver);
1219
1220 static const char *lc_messages;
1221
1222 static void
1223 usage ()
1224 {
1225   fprintf (stderr, "Usage: apt-worker check-for-updates [http_proxy]\n");
1226   fprintf (stderr, "       apt-worker rescue [package] [archives]\n");
1227   exit (1);
1228 }
1229
1230 /* Try to get the lock specified by FILE.  If this fails because
1231    someone else has the lock, a string is returned with the content of
1232    the file.  Otherwise MY_CONTENT is written to the file and NULL is
1233    returned.
1234
1235    Other kinds of failures (out of space, insufficient permissions,
1236    etc) will terminate this process.
1237
1238    The lock will be released when this process exits.
1239 */
1240
1241 static char *
1242 try_lock (const char *file, const char *my_content)
1243 {
1244   int lock_fd = open (file, O_RDWR | O_CREAT, 0640);
1245   if (lock_fd < 0)
1246     {
1247       log_stderr ("Can't open %s: %m", file);
1248       exit (1);
1249     }
1250
1251   SetCloseExec (lock_fd, true);
1252
1253   struct flock fl;
1254   fl.l_type = F_WRLCK;
1255   fl.l_whence = SEEK_SET;
1256   fl.l_start = 0;
1257   fl.l_len = 0;
1258
1259   if (fcntl (lock_fd, F_SETLK, &fl) == -1)
1260     {
1261       char buf[256];
1262       int n;
1263       
1264       if (errno == ENOLCK)
1265         {
1266           log_stderr ("locking not supported on %s: %m", file);
1267           exit (1);
1268         }
1269      
1270       /* We didn't get the lock.
1271        */
1272
1273       n = read (lock_fd, buf, 255);
1274       if (n < 0)
1275         {
1276           log_stderr ("can't read lock %s: %m", file);
1277           exit (1);
1278         }
1279
1280       buf[n] = '\0';
1281       return g_strdup (buf);
1282     }
1283
1284   /* We have the lock.
1285    */
1286
1287   if (ftruncate (lock_fd, 0) < 0)
1288     {
1289       log_stderr ("can't truncate lock %s: %m", file);
1290       exit (1);
1291     }
1292     
1293   int n = strlen (my_content);
1294   if (write (lock_fd, my_content, n) != n)
1295     {
1296       log_stderr ("can't write lock %s: %m", file);
1297       exit (1);
1298     }
1299      
1300   return NULL;
1301 }
1302
1303 static void
1304 get_apt_worker_lock (bool weak)
1305 {
1306   char *mine = g_strdup_printf ("%c %d\n", weak? 'w' : 's', getpid ());
1307   char *his = NULL;
1308   int termination_attempts = 0;
1309   int lock_attempts = 0;
1310
1311   while (true)
1312     {
1313       g_free (his);
1314       his = try_lock (APT_WORKER_LOCK, mine);
1315       
1316       if (his)
1317         {
1318           char his_type;
1319           int his_pid;
1320           
1321           if (sscanf (his, "%c %d", &his_type, &his_pid) != 2)
1322             {
1323               log_stderr ("can't parse lock.");
1324               exit (1);
1325             }
1326
1327           if (weak || his_type != 'w')
1328             {
1329               if (lock_attempts < 5)
1330                 {
1331                   lock_attempts++;
1332                   sleep (1);
1333                   continue;
1334                 }
1335               else
1336                 {
1337                   log_stderr ("too weak to get lock from %d.", his_pid);
1338                   exit (1);
1339                 }
1340             }
1341           else if (termination_attempts < 5)
1342             {
1343               termination_attempts += 1;
1344               log_stderr ("terminating %d to get lock.", his_pid);
1345               kill (his_pid, SIGTERM);
1346               sleep (1);
1347               continue;
1348             }
1349           else
1350             {
1351               /* The big hammer.
1352                */
1353               log_stderr ("killing %d to get lock.", his_pid);
1354               kill (his_pid, SIGKILL);
1355               unlink (APT_WORKER_LOCK);
1356               sleep (1);
1357               continue;
1358             }
1359         }
1360       else
1361         {
1362           /* It's ours.
1363            */
1364           g_free (mine);
1365           return;
1366         }
1367     }
1368 }
1369
1370 /* MMC default mountpoints */
1371 #define INTERNAL_MMC_MOUNTPOINT  "/home/user/MyDocs"
1372 #define REMOVABLE_MMC_MOUNTPOINT "/media/mmc1"
1373
1374 static void
1375 misc_init ()
1376 {
1377   lc_messages = getenv ("LC_MESSAGES");
1378   DBG ("LC_MESSAGES %s", lc_messages);
1379
1380   DBG ("OSSO_PRODUCT_HARDWARE %s", getenv ("OSSO_PRODUCT_HARDWARE"));
1381
1382   load_system_settings ();
1383   read_domain_conf ();
1384
1385   AptWorkerCache::Initialize ();
1386
1387   cache_init (false);
1388
1389 #ifdef HAVE_APT_TRUST_HOOK
1390   apt_set_index_trust_level_for_package_hook (index_trust_level_for_package);
1391 #endif
1392
1393   clean_temp_catalogues ();
1394
1395   // initialize the MMC mount points with defaults
1396   setenv ("INTERNAL_MMC_MOUNTPOINT", INTERNAL_MMC_MOUNTPOINT, 1);
1397   setenv ("REMOVABLE_MMC_MOUNTPOINT", REMOVABLE_MMC_MOUNTPOINT, 1);
1398 }
1399
1400 void
1401 set_options (const char *options)
1402 {
1403   if (strchr (options, 'B'))
1404     flag_break_locks = true;
1405
1406   if (strchr (options, 'D'))
1407     flag_allow_wrong_domains = true;
1408
1409   if (strchr (options, 'M'))
1410     flag_download_packages_to_mmc = true;
1411
1412   if (strchr (options, 'A'))
1413     flag_use_apt_algorithms = true;
1414 }
1415
1416 void
1417 cmd_set_options ()
1418 {
1419   const char *options = request.decode_string_in_place ();
1420   set_options (options);
1421 }
1422
1423 void
1424 cmd_set_env ()
1425 {
1426   const char *http_proxy = request.decode_string_in_place ();
1427   const char *https_proxy = request.decode_string_in_place ();
1428   const char *internal_mmc = request.decode_string_in_place ();
1429   const char *removable_mmc = request.decode_string_in_place ();
1430
1431   if (http_proxy)
1432     {
1433       setenv ("http_proxy", http_proxy, 1);
1434       DBG ("http_proxy: %s", http_proxy);
1435     }
1436
1437   if (https_proxy)
1438     {
1439       setenv ("https_proxy", https_proxy, 1);
1440       DBG ("https_proxy: %s", https_proxy);
1441     }
1442
1443   if (internal_mmc)
1444     {
1445       setenv ("INTERNAL_MMC_MOUNTPOINT", internal_mmc, 1);
1446       DBG ("INTERNAL_MMC_MOUNTPOINT: %s", internal_mmc);
1447     }
1448
1449   if (removable_mmc)
1450     {
1451       setenv ("REMOVABLE_MMC_MOUNTPOINT", removable_mmc, 1);
1452       DBG ("REMOVABLE_MMC_MOUNTPOINT: %s", removable_mmc);
1453     }
1454 }
1455
1456 char*
1457 is_fifo (const char *filename)
1458 {
1459   struct stat statstruct;
1460
1461   if ((stat (filename, &statstruct) == 0)
1462       && (S_ISFIFO (statstruct.st_mode)))
1463     return g_strdup (filename);
1464
1465   return NULL;
1466 }
1467
1468 int
1469 main (int argc, char **argv)
1470 {
1471   if (argc == 1)
1472     usage ();
1473
1474   argv += 1;
1475   argc -= 1;
1476
1477   if (!strcmp (argv[0], "backend"))
1478     {
1479       const char *options;
1480
1481       if (argc != 6)
1482         {
1483           log_stderr ("wrong invocation");
1484           exit (1);
1485         }
1486
1487       DBG ("starting up");
1488
1489       char *input_pipe = is_fifo (argv[1]);
1490       char *output_pipe = is_fifo (argv[2]);
1491       char *status_pipe = is_fifo (argv[3]);
1492       char *cancel_pipe = is_fifo (argv[4]);
1493
1494       if (!(input_pipe && output_pipe && status_pipe && cancel_pipe))
1495         {
1496           g_free (input_pipe);
1497           g_free (output_pipe);
1498           g_free (status_pipe);
1499           g_free (cancel_pipe);
1500
1501           log_stderr ("wrong fifo pipes specified");
1502           exit (1);
1503         }
1504
1505       input_fd = must_open (input_pipe, O_RDONLY | O_NONBLOCK);
1506       cancel_fd = must_open (cancel_pipe, O_RDONLY | O_NONBLOCK);
1507       output_fd = must_open (output_pipe, O_WRONLY);
1508       status_fd = must_open (status_pipe, O_WRONLY);
1509
1510       g_free (input_pipe);
1511       g_free (output_pipe);
1512       g_free (status_pipe);
1513       g_free (cancel_pipe);
1514
1515       /* This tells the frontend that the fifos are open.
1516        */
1517       send_status (op_general, 0, 0, -1);
1518
1519       /* This blocks until the frontend has opened our input fifo for
1520          writing.
1521       */
1522       block_for_read (input_fd);
1523
1524       /* Reset the O_NONBLOCK flag for the input_fd since we want to block
1525          until a new request arrives.  The cancel_fd remains in
1526          non-blocking mode since we just poll it periodically.
1527       */
1528       must_set_flags (input_fd, O_RDONLY);
1529
1530       options = argv[5];
1531
1532       DBG ("starting with pid %d, in %d, out %d, stat %d, cancel %d, options %s",
1533            getpid (), input_fd, output_fd, status_fd, cancel_fd,
1534            options);
1535
1536       set_options (options);
1537
1538       /* Don't let our heavy lifting starve the UI.
1539        */
1540       errno = 0;
1541       if (nice (20) == -1 && errno != 0)
1542         log_stderr ("nice: %m");
1543
1544       get_apt_worker_lock (false);
1545       misc_init ();
1546
1547       while (true)
1548         handle_request ();
1549
1550       return 0;
1551     }
1552   else if (!strcmp (argv[0], "check-for-updates"))
1553     {
1554       get_apt_worker_lock (true);
1555       misc_init ();
1556       return cmdline_check_updates (argv);
1557     }
1558   else if (!strcmp (argv[0], "rescue"))
1559     {
1560       return cmdline_rescue (argv);
1561     }
1562   else if (!strcmp (argv[0], "sleep"))
1563     {
1564       get_apt_worker_lock (argv[1] == NULL);
1565       while (true)
1566         {
1567           fprintf (stderr, "sleeping...\n");
1568           sleep (5);
1569         }
1570     }
1571   else
1572     usage ();
1573 }
1574
1575 /** CACHE HANDLING
1576
1577     This section contains some general purpose functions to maintain
1578     the cache of the package database.
1579
1580     The package cache can represent both the 'current' situation
1581     (i.e., the union of the information from /var/lib/dpkg/status and
1582     the various Packages files downloaded from repositories) and a
1583     'desired' situation.
1584
1585     A operation such as installing a package is performed by modifying
1586     the 'desired' situation in the cache and if that leads to a
1587     consistent configuration, the 'current' situation is brought in
1588     line with the 'desired' one by downloading the needed archives and
1589     running dpkg in an approriate way.
1590
1591     We have our own idea of what should happen when a new package (or
1592     a new version of a package) is installed, for example, and the
1593     functions in this section implement this idea.  These principal
1594     functions are available:
1595
1596     We remember which operation the cache currently represents.  That
1597     way, we can avoid recomputing it when the frontend requests the
1598     same operation multiple times in a row (which it likes to do).
1599
1600     - cache_init
1601
1602     This function creates or recreates the cache from
1603     /var/lib/dpkg/status and the various Packages file from the
1604     repositories.
1605
1606     - ensure_cache
1607
1608     This function tries to make sure that there is a valid
1609     PACKAGE_CACHE to work with.  It returns true when it succeeds and
1610     PACKAGE_CACHE is non-NULL then.  The idea is that if the cache
1611     couldn't be created in the past because of some transient error,
1612     it might be able to create it now.  Thus, every command handler
1613     that needs a cache should call ensure_cache.  When ensure_cache
1614     actually does some work, it will send STATUS messages if it was
1615     specified with its only parameter.
1616
1617     - cache_reset ()
1618
1619     This function resets the 'desired' state of the cache to be
1620     identical to the 'current' one.
1621
1622     - mark_for_install ()
1623
1624     This function modifies the 'desired' state of the cache to reflect
1625     the installation of the given package.  It will try to achieve a
1626     consistent 'desired' configuration by installing missing
1627     dependencies etc.  In general, it implements our own installation
1628     smartness.
1629
1630     - mark_for_remove ()
1631
1632     This function modifies the 'desired' state of the cache to reflect
1633     the removal of the given package.  As with mark_for_install,
1634     mark_for_removal implements our own removal smartness.
1635  */
1636
1637 /* We only report real progress information when reconstructing the
1638    cache and during downloads.  Only downloads can be cancelled.
1639
1640    The following two classes allow us to hook into libapt-pkgs
1641    progress reporting mechanism.  Instances of UPDATE_PROGESS are used
1642    for cache related activities, and instances of DOWNLOAD_STATUS are
1643    used when 'acquiring' things.
1644 */
1645
1646 class UpdateProgress : public OpProgress
1647 {
1648   bool with_status;
1649
1650   virtual void
1651   Update ()
1652   {
1653     if (with_status)
1654       send_status (op_general, (int)Percent, 100, 5);
1655   }
1656
1657 public:
1658   UpdateProgress (bool ws) : with_status (ws) { }
1659 };
1660
1661 class DownloadStatus : public pkgAcquireStatus
1662 {
1663   virtual bool
1664   MediaChange (string Media, string Drive)
1665   {
1666     return false;
1667   }
1668
1669   virtual bool
1670   Pulse (pkgAcquire *Owner)
1671   {
1672     pkgAcquireStatus::Pulse (Owner);
1673
1674     send_status (op_downloading, (int)CurrentBytes, (int)TotalBytes, 1000);
1675
1676     /* The cancel_fd is in non-blocking mode.
1677      */
1678     if (read_byte (cancel_fd) >= 0)
1679       return false;
1680
1681     return true;
1682   }
1683 };
1684
1685 bool
1686 is_user_section (const char *section, const char *end)
1687 {
1688   if (section == NULL)
1689     return false;
1690
1691 #if ENABLE_OLD_MAEMO_SECTION_TEST
1692   if (end-section > 6 && !strncmp (section, "maemo/", 6))
1693     return true;
1694 #endif
1695   
1696   return end-section > 5 && !strncmp (section, "user/", 5);
1697 }
1698
1699 bool
1700 is_user_package (const pkgCache::VerIterator &ver)
1701 {
1702   const char *section = ver.Section ();
1703
1704   if (section == NULL)
1705     return false;
1706
1707   return is_user_section (section, section + strlen (section));
1708 }
1709
1710 /* Our own version of debSystem.  We override the Lock member function
1711    to be able to break locks and to avoid failing when dpkg has left a
1712    journal.
1713 */
1714
1715 class mydebSystem : public debSystem
1716 {
1717   // For locking support
1718   int LockFD;
1719   unsigned LockCount;
1720
1721 public:
1722
1723   virtual signed Score (Configuration const &Cnf);
1724   virtual bool Lock ();
1725   virtual bool UnLock (bool NoErrors);
1726   
1727   mydebSystem ();
1728 };
1729
1730 mydebSystem::mydebSystem ()
1731   : debSystem ()
1732 {
1733    Label = "handsfree Debian dpkg interface";
1734 }
1735
1736 signed
1737 mydebSystem::Score (Configuration const &Cnf)
1738 {
1739   return debSystem::Score (Cnf) + 10;  // Pick me, pick me, pick me!
1740 }
1741
1742 bool
1743 mydebSystem::Lock ()
1744 {
1745   /* This is a modified copy of debSystem::Lock, which in turn is a
1746      copy of the behavior of dpkg.
1747   */
1748
1749   // Disable file locking
1750   if (_config->FindB("Debug::NoLocking",false) == true || LockCount > 1)
1751     {
1752       LockCount++;
1753       return true;
1754     }
1755
1756   // Create the lockfile, breaking the lock if requested.
1757   string AdminDir = flNotFile(_config->Find("Dir::State::status"));
1758   LockFD = ForceLock(AdminDir + "lock");
1759   if (LockFD == -1)
1760     {
1761       if (errno == EACCES || errno == EAGAIN)
1762         return _error->Error("Unable to lock the administration directory (%s), "
1763                              "is another process using it?",AdminDir.c_str());
1764       else
1765         return _error->Error("Unable to lock the administration directory (%s), "
1766                              "are you root?",AdminDir.c_str());
1767     }
1768
1769   LockCount++;
1770       
1771   return true;
1772 }
1773
1774 // System::UnLock - Drop a lock                                         /*{{{*/
1775 // ---------------------------------------------------------------------
1776 /* */
1777 bool mydebSystem::UnLock(bool NoErrors)
1778 {
1779    if (LockCount == 0 && NoErrors == true)
1780       return false;
1781    
1782    if (LockCount < 1)
1783       return _error->Error("Not locked");
1784    if (--LockCount == 0)
1785    {
1786       close(LockFD);
1787       LockCount = 0;
1788    }
1789    
1790    return true;
1791 }
1792                                                                         /*}}}*/
1793 mydebSystem mydebsystem;
1794
1795 static void
1796 clear_dpkg_updates ()
1797 {
1798   string File = flNotFile(_config->Find("Dir::State::status")) + "updates/";
1799   DIR *DirP = opendir(File.c_str());
1800   if (DirP == 0)
1801     return;
1802    
1803   /* We ignore any files that are not all digits, this skips .,.. and 
1804      some tmp files dpkg will leave behind.. */
1805
1806   for (struct dirent *Ent = readdir(DirP); Ent != 0; Ent = readdir(DirP))
1807     {
1808       bool ignore = false;
1809
1810       for (unsigned int I = 0; Ent->d_name[I] != 0; I++)
1811         {
1812           // Check if its not a digit..
1813           if (isdigit(Ent->d_name[I]) == 0)
1814             {
1815               ignore = true;
1816               break;
1817             }
1818         }
1819
1820       if (!ignore)
1821         {
1822           log_stderr ("Running 'dpkg --configure dpkg' "
1823                       "to clean up the journal.");
1824           system ("dpkg --configure dpkg");
1825           break;
1826         }
1827     }
1828
1829    closedir(DirP);
1830 }
1831
1832 void cache_reset ();
1833
1834 /* The operation represented by the cache.
1835  */
1836 static char *current_cache_package = NULL;
1837 static bool current_cache_is_install;
1838
1839 static bool
1840 check_cache_state (const char *package, bool is_install)
1841 {
1842   if (current_cache_package
1843       && current_cache_is_install == is_install
1844       && strcmp (current_cache_package, package) == 0)
1845     return true;
1846
1847   if (current_cache_package)
1848     cache_reset ();
1849
1850   current_cache_package = g_strdup (package);
1851   current_cache_is_install = is_install;
1852   return false;
1853 }
1854
1855 /* Initialize libapt-pkg if this has not been done already and
1856    (re-)create PACKAGE_CACHE.  If the cache can not be created,
1857    PACKAGE_CACHE is set to NULL and an appropriate message is output.
1858    */
1859 void
1860 cache_init (bool with_status)
1861 {
1862   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
1863
1864   /* Closes the cache, to prevent getting blocked by other locks in
1865    * dpkg structures. If we don't do it, changing the apt worker state
1866    * does not remove the dpkg state lock and then fails on trying to
1867    * run dpkg */
1868   /* @todo do we really keep doing this? */
1869   if (awc->cache)
1870     {
1871       DBG ("closing");
1872       delete awc->action_group;
1873       awc->cache->Close ();
1874       delete awc->cache;
1875       awc->cache = 0;
1876       DBG ("done");
1877     }
1878
1879   /* We need to dump the errors here since any pending errors will
1880      cause the following operations to fail.
1881   */
1882   _error->DumpErrors ();
1883
1884   /* Clear out the dpkg journal before construction the cache.
1885    */
1886   clear_dpkg_updates ();
1887
1888   UpdateProgress progress (with_status);
1889   awc->cache = new myCacheFile;
1890
1891   DBG ("init.");
1892   if (!awc->cache->Open (progress))
1893     {
1894       DBG ("failed.");
1895       _error->DumpErrors ();
1896       delete awc->cache;
1897       awc->cache = 0;
1898     }
1899
1900   if (awc->cache)
1901     {
1902       /* We create a ActionGroup here that is active for the whole
1903          lifetime of the cache.  This prevents libapt-pkg from
1904          performing certain expensive operations that we don't need to
1905          be done intermediately, such as garbage collection.
1906       */
1907       pkgDepCache &cache = *awc->cache;
1908       awc->action_group = new pkgDepCache::ActionGroup (cache);
1909     }
1910
1911   cache_reset ();
1912
1913   if (awc->cache)
1914     write_available_updates_file ();
1915 }
1916
1917 bool
1918 ensure_cache (bool with_status)
1919 {
1920   AptWorkerCache * awc = 0;
1921   
1922   awc = AptWorkerCache::GetCurrent ();
1923   if (awc->cache == NULL)
1924     cache_init (with_status);
1925
1926   return awc->cache != NULL;
1927 }
1928
1929 /* Determine whether a package was installed automatically to satisfy
1930    a dependency.
1931 */
1932 bool
1933 is_auto_package (pkgCache::PkgIterator &pkg)
1934 {
1935   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
1936   pkgDepCache &cache = *(awc->cache);
1937   
1938   return (cache[pkg].Flags & pkgCache::Flag::Auto) != 0;
1939 }
1940
1941 /* Determine whether a package is related to the current operation.
1942 */
1943 bool
1944 is_related (pkgCache::PkgIterator &pkg)
1945 {
1946   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
1947   return awc->cache->extra_info[pkg->ID].related;
1948 }
1949
1950 void
1951 mark_related (const pkgCache::VerIterator &ver)
1952 {
1953   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
1954   const pkgCache::PkgIterator &pkg = ver.ParentPkg();
1955
1956   if (awc->cache->extra_info[pkg->ID].related)
1957     return;
1958
1959   awc->cache->extra_info[pkg->ID].related = true;
1960
1961   pkgDepCache &cache = *awc->cache;
1962
1963   if (pkg.State() == pkgCache::PkgIterator::NeedsUnpack)
1964     cache.SetReInstall (pkg, true);
1965
1966   /* When there are some packages that might need configuring or
1967      unpacking, we also mark all dependencies of this package as
1968      related so that we try to unpack/configure them as well.
1969   */
1970   if (cache.BadCount () > 0)
1971     {
1972       for (pkgCache::DepIterator D = ver.DependsList(); D.end() == false;
1973            D++)
1974         {
1975           const pkgCache::PkgIterator &dep_pkg = D.TargetPkg ();
1976           const pkgCache::VerIterator &dep_ver = dep_pkg.CurrentVer ();
1977           if (!dep_ver.end())
1978             mark_related (dep_ver);
1979         }
1980     }
1981 }
1982
1983 /* Revert the cache to its initial state.  More concretely, all
1984    packages are marked as 'keep' and 'unrelated'.
1985
1986    XXX - let libapt-pkg handle the auto flags.
1987 */
1988 void
1989 cache_reset_package (pkgCache::PkgIterator &pkg)
1990 {
1991   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
1992   pkgDepCache &cache = *(awc->cache);
1993
1994   cache.MarkKeep (pkg);
1995
1996   if (awc->cache->extra_info[pkg->ID].autoinst)
1997     cache[pkg].Flags |= pkgCache::Flag::Auto;
1998   else
1999     cache[pkg].Flags &= ~pkgCache::Flag::Auto;
2000   
2001   awc->cache->extra_info[pkg->ID].related = false;
2002   awc->cache->extra_info[pkg->ID].soft = false;
2003 }
2004
2005 static bool
2006 any_newly_or_related_broken ()
2007 {
2008   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2009   if (awc->cache == NULL)
2010     return false;
2011
2012   pkgDepCache &cache = *(awc->cache);
2013   for (pkgCache::PkgIterator pkg = cache.PkgBegin(); !pkg.end (); pkg++)
2014     {
2015       if (cache[pkg].InstBroken() &&
2016           (!cache[pkg].NowBroken() || is_related (pkg)))
2017         return true;
2018     }
2019   return false;
2020 }
2021
2022 void
2023 cache_reset ()
2024 {
2025   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2026   if (awc->cache == NULL)
2027     return;
2028
2029   pkgDepCache &cache = *(awc->cache);
2030
2031   for (pkgCache::PkgIterator pkg = cache.PkgBegin(); !pkg.end (); pkg++)
2032     cache_reset_package (pkg);
2033
2034   g_free (current_cache_package);
2035   current_cache_package = NULL;
2036 }
2037
2038 /* Try to fix packages that have been broken by undoing soft changes.
2039
2040    This is not really complicated, the code only looks impenetrable
2041    because of libapt-pkg's data structures.
2042
2043    For each package that is broken for the planned operation, we try
2044    to fix it by undoing the removal of softly removed packages that it
2045    depends on.  We do this in a loop since a package that has been put
2046    back might be broken itself and be in need of fixing.
2047 */
2048 void
2049 fix_soft_packages ()
2050 {
2051   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2052   if (awc->cache == NULL)
2053     return;
2054
2055   pkgDepCache &cache = *(awc->cache);
2056
2057   bool something_changed;
2058
2059   do 
2060     {
2061       DBG ("FIX");
2062
2063       something_changed = false;
2064       for (pkgCache::PkgIterator pkg = cache.PkgBegin(); !pkg.end (); pkg++)
2065         {
2066           if (cache[pkg].InstBroken())
2067             {
2068               pkgCache::DepIterator Dep =
2069                 cache[pkg].InstVerIter(cache).DependsList();
2070               for (; Dep.end() != true;)
2071                 {
2072                   // Grok or groups
2073                   pkgCache::DepIterator Start = Dep;
2074                   bool Result = true;
2075                   for (bool LastOR = true;
2076                        Dep.end() == false && LastOR == true;
2077                        Dep++)
2078                     {
2079                       LastOR = ((Dep->CompareOp & pkgCache::Dep::Or)
2080                                 == pkgCache::Dep::Or);
2081                     
2082                       if ((cache[Dep] & pkgDepCache::DepInstall)
2083                           == pkgDepCache::DepInstall)
2084                         Result = false;
2085                     }
2086                 
2087                   // Dep is satisfied okay.
2088                   if (Result == false)
2089                     continue;
2090
2091                   // Try to fix it by putting back the first softly
2092                   // removed target
2093
2094                   for (bool LastOR = true;
2095                        Start.end() == false && LastOR == true;
2096                        Start++)
2097                     {
2098                       LastOR = ((Start->CompareOp & pkgCache::Dep::Or)
2099                                 == pkgCache::Dep::Or);
2100                     
2101                       pkgCache::PkgIterator Pkg = Start.TargetPkg ();
2102
2103                       if (((cache[Start] & pkgDepCache::DepInstall)
2104                            != pkgDepCache::DepInstall)
2105                           && !Pkg.end()
2106                           && cache[Pkg].Delete()
2107               && awc->cache->extra_info[Pkg->ID].soft)
2108                         {
2109                           DBG ("= %s", Pkg.Name());
2110                           cache_reset_package (Pkg);
2111                           something_changed = true;
2112                           break;
2113                         }
2114                     }
2115                 }
2116             }
2117         }
2118     } while (something_changed);
2119 }
2120
2121 /* Determine whether PKG replaces TARGET.
2122  */
2123 static bool
2124 package_replaces (pkgCache::PkgIterator &pkg,
2125                   pkgCache::PkgIterator &target)
2126 {
2127   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2128   pkgDepCache &cache = *(awc->cache);
2129
2130   pkgCache::DepIterator Dep = cache[pkg].InstVerIter(cache).DependsList();
2131   for (; Dep.end() != true; Dep++)
2132     {
2133       if (Dep->Type == pkgCache::Dep::Replaces)
2134         {
2135           SPtrArray<pkgCache::Version *> List = Dep.AllTargets();
2136           for (pkgCache::Version **I = List; *I != 0; I++)
2137             {
2138               pkgCache::VerIterator Ver(cache,*I);
2139               pkgCache::PkgIterator Pkg = Ver.ParentPkg();
2140           
2141               if (Pkg == target)
2142                 return true;
2143             }
2144         }
2145     }
2146   return false;
2147 }
2148
2149 #if 0
2150 /* Determine whether PKG is a critical dependency of other packages
2151    thata re going to be installed.
2152  */
2153 static bool
2154 package_is_needed (pkgCache::PkgIterator &pkg)
2155 {
2156   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2157   pkgDepCache &cache = *(awc->cache);
2158
2159   pkgCache::DepIterator Dep = pkg.RevDependsList();
2160   for (; Dep.end() != true; Dep++)
2161     {
2162       if (Dep->Type == pkgCache::Dep::PreDepends
2163           || Dep->Type == pkgCache::Dep::Depends)
2164         {
2165           pkgCache::PkgIterator other_pkg = Dep.ParentPkg();
2166           pkgCache::VerIterator other_ver = Dep.ParentVer();
2167           pkgCache::VerIterator inst_ver = cache[other_pkg].InstVerIter(cache);
2168
2169           if (other_ver == inst_ver)
2170             return true;
2171         }
2172     }
2173   return false;
2174 }
2175 #endif
2176
2177 /* Mark a package for installation, using a 'no-surprises' approach
2178    suitable for the Application Manager.
2179
2180    Concretely, installing a package will never automatically remove
2181    other packages.  Thus, we undo the removals scheduled by
2182    MarkInstall.  Doing this will break the original package, but that
2183    is what we want.
2184 */
2185
2186 static void mark_for_remove_1 (pkgCache::PkgIterator &pkg, bool soft);
2187
2188 static void
2189 mark_for_install_1 (pkgCache::PkgIterator &pkg, int level)
2190 {
2191   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2192   pkgDepCache &cache = *(awc->cache);
2193
2194   /* This check is just to be extra robust against infinite
2195      recursions.  They shouldn't happen, but you never know...
2196   */
2197   if (level > 100)
2198     return;
2199
2200   mark_related (cache[pkg].CandidateVerIter(cache));
2201
2202   /* Avoid recursion if package is already marked for installation but
2203      try to fix it when it is broken.
2204    */
2205   if (cache[pkg].Mode == pkgDepCache::ModeInstall
2206       && !cache[pkg].InstBroken ())
2207     return;
2208
2209   DBG ("+ %s", pkg.Name());
2210
2211   /* Now mark it and return if that fails.  Both ModeInstall and
2212      ModeKeep are fine.  ModeKeep only happens for broken packages.
2213    */
2214   cache.MarkInstall (pkg, false);
2215   if (cache[pkg].Mode != pkgDepCache::ModeInstall
2216       && cache[pkg].Mode != pkgDepCache::ModeKeep)
2217     return;
2218
2219   /* Try to satisfy dependencies.  We can't use MarkInstall with
2220      AutoInst == true since we don't like how it handles conflicts,
2221      and we have our own way of uninstalling packages.
2222
2223      The code below is lifted from pkgDepCache::MarkInstall.  Sorry
2224      for introducing this mess here.
2225   */
2226
2227   pkgCache::DepIterator Dep = cache[pkg].InstVerIter(cache).DependsList();
2228   for (; Dep.end() != true;)
2229     {
2230       // Grok or groups
2231       pkgCache::DepIterator Start = Dep;
2232       bool Result = true;
2233       unsigned Ors = 0;
2234       for (bool LastOR = true; Dep.end() == false && LastOR == true;
2235            Dep++,Ors++)
2236         {
2237           LastOR = (Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
2238
2239           if ((cache[Dep] & pkgDepCache::DepInstall) == pkgDepCache::DepInstall)
2240             Result = false;
2241         }
2242       
2243       // Dep is satisfied okay.
2244       if (Result == false)
2245         continue;
2246
2247       /* Check if this dep should be consider for install. If it is a user
2248          defined important dep and we are installed a new package then 
2249          it will be installed. Otherwise we only worry about critical deps */
2250       if (cache.IsImportantDep(Start) == false)
2251         continue;
2252
2253       if (pkg->CurrentVer != 0 && Start.IsCritical() == false)
2254         continue;
2255       
2256       /* If we are in an or group locate the first or that can 
2257          succeed. We have already cached this.. */
2258       for (; Ors > 1 
2259              && (cache[Start] & pkgDepCache::DepCVer) != pkgDepCache::DepCVer;
2260            Ors--)
2261         Start++;
2262
2263       /* This bit is for processing the possibilty of an install/upgrade
2264          fixing the problem */
2265       SPtrArray<pkgCache::Version *> List = Start.AllTargets();
2266       if ((cache[Start] & pkgDepCache::DepCVer) == pkgDepCache::DepCVer)
2267         {
2268           // Right, find the best version to install..
2269           pkgCache::Version **Cur = List;
2270           pkgCache::PkgIterator P = Start.TargetPkg();
2271           pkgCache::PkgIterator InstPkg(cache,0);
2272          
2273           // See if there are direct matches (at the start of the list)
2274           for (; *Cur != 0 && (*Cur)->ParentPkg == P.Index(); Cur++)
2275             {
2276               pkgCache &pkgcache = cache.GetCache ();
2277               pkgCache::PkgIterator Pkg(pkgcache,
2278                                         pkgcache.PkgP + (*Cur)->ParentPkg);
2279               if (cache[Pkg].CandidateVer != *Cur)
2280                 continue;
2281               InstPkg = Pkg;
2282               break;
2283             }
2284
2285           // Select the highest priority providing package
2286           if (InstPkg.end() == true)
2287             {
2288               pkgPrioSortList(cache,Cur);
2289               for (; *Cur != 0; Cur++)
2290                 {
2291                   pkgCache &pkgcache = cache.GetCache ();
2292                   pkgCache::PkgIterator
2293                     Pkg(pkgcache,pkgcache.PkgP + (*Cur)->ParentPkg);
2294                   if (cache[Pkg].CandidateVer != *Cur)
2295                     continue;
2296                   InstPkg = Pkg;
2297                   break;
2298                 }
2299             }
2300           
2301           if (InstPkg.end() == false)
2302             {
2303               mark_for_install_1 (InstPkg, level + 1);
2304
2305               // Set the autoflag, after MarkInstall because
2306               // MarkInstall unsets it
2307               if (P->CurrentVer == 0)
2308                 cache[InstPkg].Flags |= pkgCache::Flag::Auto;
2309             }
2310
2311           continue;
2312         }
2313
2314       /* For conflicts/replaces combinations we de-install the package
2315          with mark_for_remove, but only if it is a non-user package.
2316          (Conflicts and Replaces may not have or groups.)
2317       */
2318       if (Start->Type == pkgCache::Dep::Conflicts
2319           || Start->Type == pkgCache::Dep::Obsoletes)
2320         {
2321           for (pkgCache::Version **I = List; *I != 0; I++)
2322             {
2323               pkgCache::VerIterator Ver(cache,*I);
2324               pkgCache::PkgIterator target = Ver.ParentPkg();
2325
2326               if (!is_user_package (Ver)
2327                   && package_replaces (pkg, target))
2328                 mark_for_remove_1 (target, true);
2329             }
2330           continue;
2331         }
2332     }
2333 }
2334
2335 static void
2336 mark_for_install (pkgCache::PkgIterator &pkg)
2337 {
2338   DBG ("INSTALL %s", pkg.Name());
2339
2340   if (flag_use_apt_algorithms)
2341     {
2342       AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2343       pkgDepCache &Cache = *(awc->cache);
2344       pkgDepCache::StateCache &State = Cache[pkg];
2345
2346       pkgProblemResolver Fix(&Cache);
2347
2348       Fix.Clear(pkg);
2349       Fix.Protect(pkg);   
2350
2351       Cache.MarkInstall(pkg,false);
2352       if (State.Install() == false)
2353         {
2354           if (pkg->CurrentVer && pkg.CurrentVer().Downloadable())
2355             Cache.SetReInstall(pkg,true);
2356         } 
2357
2358       // Install it with autoinstalling enabled (if we not respect the minial
2359       // required deps or the policy)
2360       if (State.InstBroken() == true || State.InstPolicyBroken() == true)
2361         Cache.MarkInstall(pkg,true);
2362
2363       Fix.InstallProtect();
2364       if (Fix.Resolve(true) == false)
2365          _error->Discard();
2366     }
2367   else
2368     {
2369       mark_for_install_1 (pkg, 0);
2370       fix_soft_packages ();
2371     }
2372 }
2373
2374 /* Mark every upgradeable non-user package for installation.
2375  */
2376 static void
2377 mark_sys_upgrades ()
2378 {
2379   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2380   pkgDepCache &cache = *(awc->cache);
2381
2382   DBG ("UPGRADE");
2383
2384   for (pkgCache::PkgIterator p = cache.PkgBegin (); !p.end (); p++)
2385     {
2386       if (!p.CurrentVer().end()
2387           && !is_user_package (p.CurrentVer())
2388           && cache[p].Keep())
2389         mark_for_install_1 (p, 0);
2390     }
2391   fix_soft_packages ();
2392 }
2393
2394 /* Mark the named package for installation.  This function also
2395    handles magic packages like "magic:sys".
2396 */
2397
2398 static bool
2399 mark_named_package_for_install (const char *package)
2400 {
2401   if (check_cache_state (package, true))
2402     return true;
2403
2404   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2405   if (!strcmp (package, "magic:sys"))
2406     {
2407       mark_sys_upgrades ();
2408       return true;
2409     }
2410   else
2411     {
2412       pkgDepCache &cache = *(awc->cache);
2413       pkgCache::PkgIterator pkg = cache.FindPkg (package);
2414       if (!pkg.end())
2415         {
2416           mark_for_install (pkg);
2417           return true;
2418         }
2419       else
2420         return false;
2421     }
2422 }
2423
2424 /* Mark a package for removal and also remove as many of the packages
2425    that it depends on as possible.
2426 */
2427 static void
2428 mark_for_remove_1 (pkgCache::PkgIterator &pkg, bool soft)
2429 {
2430   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2431   pkgDepCache &cache = *(awc->cache);
2432
2433   if (cache[pkg].Delete ())
2434     return;
2435
2436   DBG ("- %s%s", pkg.Name(), soft? " (soft)" : "");
2437
2438   cache.MarkDelete (pkg);
2439   cache[pkg].Flags &= ~pkgCache::Flag::Auto;
2440   awc->cache->extra_info[pkg->ID].soft = soft;
2441
2442   if (!cache[pkg].Delete ())
2443     return;
2444
2445   // Now try to remove all non-user, auto-installed dependencies of
2446   // this package.
2447
2448   pkgCache::VerIterator cur = pkg.CurrentVer ();
2449   if (cur.end ())
2450     return;
2451
2452   for (pkgCache::DepIterator dep = cur.DependsList(); dep.end() == false;
2453        dep++)
2454     {
2455       if (dep->Type == pkgCache::Dep::PreDepends ||
2456           dep->Type == pkgCache::Dep::Depends)
2457         {
2458           pkgCache::PkgIterator p = dep.TargetPkg ();
2459           if (!p.end ()
2460               && is_auto_package (p)
2461               && !p.CurrentVer().end()
2462               && !is_user_package (p.CurrentVer()))
2463             mark_for_remove_1 (p, true);
2464         }
2465     }
2466 }
2467
2468 static void
2469 mark_for_remove (pkgCache::PkgIterator &pkg)
2470 {
2471   DBG ("REMOVE %s", pkg.Name());
2472
2473   if (check_cache_state (pkg.Name (), false))
2474     return;
2475
2476   if (flag_use_apt_algorithms)
2477     {
2478       AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2479       pkgDepCache &Cache = *(awc->cache);
2480
2481       pkgProblemResolver Fix(&Cache);
2482
2483       Fix.Clear(pkg);
2484       Fix.Protect(pkg);   
2485
2486       Fix.Remove(pkg);
2487       Cache.MarkDelete (pkg,false);
2488
2489       Fix.InstallProtect();
2490       if (Fix.Resolve(true) == false)
2491          _error->Discard();
2492     }
2493   else
2494     {
2495       mark_for_remove_1 (pkg, false);
2496       fix_soft_packages ();
2497     }
2498 }
2499
2500 /* Getting the package record in a nicely parsable form.
2501  */
2502
2503 struct package_record {
2504   pkgRecords Recs;
2505   pkgRecords::Parser &P;
2506   pkgTagSection section;
2507   bool valid;
2508
2509   package_record (pkgCache::VerIterator &ver);
2510
2511   bool has (const char *tag);
2512   string get_string (const char *tag);
2513   char *get (const char *tag);
2514   int get_int (const char *tag, int def);
2515
2516   string get_localized_string (const char *tag);
2517 };
2518
2519 package_record::package_record (pkgCache::VerIterator &ver)
2520   : Recs (*(AptWorkerCache::GetCurrent ()->cache)),
2521     P (Recs.Lookup (ver.FileList ()))
2522 {
2523   const char *start, *stop;
2524   P.GetRec (start, stop);
2525
2526   /* NOTE: pkTagSection::Scan only succeeds when the record ends in
2527            two newlines, but pkgRecords::Parser::GetRec does not
2528            include the second newline in its returned region.
2529            However, that second newline is always there, so we just
2530            pass one more character to Scan.
2531   */
2532   
2533   valid = section.Scan (start, stop-start+1);
2534 }
2535
2536 bool
2537 package_record::has (const char *tag)
2538 {
2539   unsigned pos;
2540   return valid && section.Find (tag, pos);
2541 }
2542
2543 string
2544 package_record::get_string (const char *tag)
2545 {
2546   if (valid)
2547     return section.FindS (tag);
2548   else
2549     return string ("");
2550 }
2551  
2552 int
2553 all_white_space (const char *text)
2554 {
2555   while (*text)
2556     if (!isspace (*text++))
2557       return 0;
2558   return 1;
2559 }
2560
2561 char *
2562 package_record::get (const char *tag)
2563 {
2564   if (!valid)
2565     return NULL;
2566
2567   string res = get_string (tag);
2568   if (all_white_space (res.c_str ()))
2569     return NULL;
2570   else
2571     return g_strdup (res.c_str());
2572 }
2573
2574 int
2575 package_record::get_int (const char *tag, int def)
2576 {
2577   if (!valid)
2578     return def;
2579
2580   return section.FindI (tag, def);
2581 }
2582
2583 string
2584 package_record::get_localized_string (const char *tag)
2585 {
2586   if (lc_messages && *lc_messages)
2587     {
2588       char *locale_tag = g_strdup_printf ("%s-%s", tag, lc_messages);
2589
2590       if (has (locale_tag))
2591         {
2592           string res = get_string (locale_tag);
2593           g_free (locale_tag);
2594           return res;
2595         }
2596       g_free (locale_tag);
2597     }
2598
2599   return get_string (tag);
2600 }
2601
2602 /** COMMAND HANDLERS
2603  */
2604
2605 /* APTCMD_GET_PACKAGE_LIST 
2606
2607    The get_package_list command can do some filtering and we have a
2608    few utility functions for implementing the necessary checks.  The
2609    check generally take cache iterators to identify a package or a
2610    version.
2611  */
2612
2613 bool
2614 name_matches_pattern (pkgCache::PkgIterator &pkg,
2615                       const char *pattern)
2616 {
2617   bool match = false;
2618   char **words = g_strsplit (pattern, " ", 0);
2619   int i;
2620
2621   if (words == NULL)
2622     return false;
2623
2624   for (i = 0; words[i] != NULL; i++)
2625     if (strcasestr (pkg.Name(), words[i]))
2626       match = true;
2627     else
2628       {
2629         match = false;
2630         break;
2631       }
2632
2633   g_strfreev (words);
2634   return match;
2635 }
2636
2637 bool
2638 description_matches_pattern (pkgCache::VerIterator &ver,
2639                              const char *pattern)
2640 {
2641   bool match = false;
2642   char **words = g_strsplit (pattern, " ", 0);
2643   package_record rec (ver);
2644   const char *desc = rec.P.LongDesc().c_str();
2645   int i;
2646
2647   if (words == NULL)
2648     return false;
2649
2650   for (i = 0; words[i] != NULL; i++)
2651     if (strcasestr (desc, words[i]))  // XXX - UTF8?
2652       match = true;
2653     else
2654       {
2655         match = false;
2656         break;
2657       }
2658
2659   g_strfreev (words);
2660   return match;
2661 }
2662
2663 static string
2664 get_description (int summary_kind,
2665                  pkgCache::PkgIterator &pkg,
2666                  package_record &rec)
2667 {
2668   string res;
2669
2670   if (summary_kind == 1 && !pkg.CurrentVer().end())
2671     res = rec.get_localized_string ("Maemo-Upgrade-Description");
2672
2673   if (res.empty())
2674     {
2675       /* XXX - support apt's own method of localizing descriptions as
2676                well.
2677       */
2678       res = rec.get_localized_string ("Description");
2679     }
2680
2681   return res;
2682 }
2683
2684 static string
2685 get_short_description (int summary_kind,
2686                        pkgCache::PkgIterator &pkg,
2687                        package_record &rec)
2688 {
2689   string res = get_description (summary_kind, pkg, rec);
2690   string::size_type pos = res.find('\n');
2691   if (pos != string::npos)
2692     return string (res,0,pos);
2693   return res;
2694 }
2695
2696 static string
2697 get_long_description (int summary_kind,
2698                       pkgCache::PkgIterator &pkg,
2699                       package_record &rec)
2700 {
2701   return get_description (summary_kind, pkg, rec);
2702 }
2703
2704 static char *
2705 get_icon (package_record &rec)
2706 {
2707   return rec.get ("Maemo-Icon-26");
2708 }
2709
2710 struct flag_struct {
2711   const char *name;
2712   int flag;
2713 } flag_names[] = {
2714   { "close-apps",       pkgflag_close_apps },
2715   { "suggest-backup",   pkgflag_suggest_backup },
2716   { "reboot",           pkgflag_reboot },
2717   { "system-update",    pkgflag_system_update },
2718   { "flash-and-reboot", pkgflag_flash_and_reboot },
2719   { NULL,               0 }
2720 };
2721
2722 static int
2723 get_flags (package_record &rec)
2724 {
2725   int flags = 0;
2726   char *flag_string = rec.get ("Maemo-Flags");
2727   char *ptr = flag_string, *tok;
2728   while ((tok = strsep (&ptr, ",")))
2729     {
2730       for (int i = 0; flag_names[i].name != NULL; i++)
2731         if (tokens_equal (flag_names[i].name, tok))
2732           {
2733             flags |= flag_names[i].flag;
2734             break;
2735           }
2736     }
2737   g_free (flag_string);
2738
2739   return flags;
2740 }
2741
2742 static string
2743 get_pretty_name (package_record &rec)
2744 {
2745   return rec.get_localized_string ("Maemo-Display-Name");
2746 }
2747
2748 static int64_t
2749 get_required_free_space (package_record &rec)
2750 {
2751   return 1024 * (int64_t) rec.get_int ("Maemo-Required-Free-Space", 0);
2752 }
2753
2754 static void
2755 encode_version_info (int summary_kind,
2756                      pkgCache::VerIterator &ver, bool include_size)
2757 {
2758   package_record rec (ver);
2759   char *icon;
2760
2761   response.encode_string (ver.VerStr ());
2762   if (include_size)
2763     response.encode_int64 (ver->InstalledSize);
2764   response.encode_string (ver.Section ());
2765   string pretty = get_pretty_name (rec);
2766   response.encode_string (pretty.empty()? NULL : pretty.c_str());
2767   pkgCache::PkgIterator pkg = ver.ParentPkg();
2768   response.encode_string 
2769     (get_short_description (summary_kind, pkg, rec).c_str());
2770   icon = get_icon (rec);
2771   response.encode_string (icon);
2772   g_free (icon);
2773 }
2774
2775 static void
2776 encode_empty_version_info (bool include_size)
2777 {
2778   response.encode_string (NULL);
2779   if (include_size)
2780     response.encode_int64 (0);
2781   response.encode_string (NULL);
2782   response.encode_string (NULL);
2783   response.encode_string (NULL);
2784   response.encode_string (NULL);
2785 }
2786
2787 void
2788 cmd_get_package_list ()
2789 {
2790   AptWorkerCache *awc = AptWorkerCache::GetCurrent ();
2791   bool only_user = request.decode_int ();
2792   bool only_installed = request.decode_int ();
2793   bool only_available = request.decode_int ();
2794   const char *pattern = request.decode_string_in_place ();
2795   bool show_magic_sys = request.decode_int ();
2796
2797   if (!ensure_cache (true))
2798     {
2799       response.encode_int (0);
2800       return;
2801     }
2802
2803   response.encode_int (1);
2804   pkgDepCache &cache = *(awc->cache);
2805
2806   for (pkgCache::PkgIterator pkg = cache.PkgBegin(); !pkg.end (); pkg++)
2807     {
2808       int flags = 0;
2809
2810       /* Get installed and candidate iterators for current package */
2811       pkgCache::VerIterator installed = pkg.CurrentVer ();
2812       pkgCache::VerIterator candidate = cache[pkg].CandidateVerIter(cache);
2813
2814       // s