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