]> git.saurik.com Git - apt-legacy.git/blame - apt-pkg/deb/dpkgpm.cc
Attempt to skip and resync any seriously broken semantics in package sections.
[apt-legacy.git] / apt-pkg / deb / dpkgpm.cc
CommitLineData
da6ee469
JF
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: dpkgpm.cc,v 1.28 2004/01/27 02:25:01 mdz Exp $
4/* ######################################################################
5
6 DPKG Package Manager - Provide an interface to dpkg
7
8 ##################################################################### */
9 /*}}}*/
10// Includes /*{{{*/
da6ee469
JF
11#include <apt-pkg/dpkgpm.h>
12#include <apt-pkg/error.h>
13#include <apt-pkg/configuration.h>
14#include <apt-pkg/depcache.h>
15#include <apt-pkg/strutl.h>
00ec24d0
JF
16#include <apti18n.h>
17#include <apt-pkg/fileutl.h>
da6ee469
JF
18
19#include <unistd.h>
20#include <stdlib.h>
21#include <fcntl.h>
00ec24d0 22#include <sys/select.h>
da6ee469
JF
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <signal.h>
26#include <errno.h>
27#include <stdio.h>
00ec24d0
JF
28#include <string.h>
29#include <algorithm>
da6ee469
JF
30#include <sstream>
31#include <map>
32
00ec24d0
JF
33#include <termios.h>
34#include <unistd.h>
35#include <sys/ioctl.h>
36#include <sys/stat.h>
37#include <util.h>
38
da6ee469
JF
39#include <config.h>
40#include <apti18n.h>
41 /*}}}*/
42
43using namespace std;
44
00ec24d0
JF
45namespace
46{
47 // Maps the dpkg "processing" info to human readable names. Entry 0
48 // of each array is the key, entry 1 is the value.
49 const std::pair<const char *, const char *> PackageProcessingOps[] = {
50 std::make_pair("install", N_("Installing %s")),
51 std::make_pair("configure", N_("Configuring %s")),
52 std::make_pair("remove", N_("Removing %s")),
0e5943eb 53 std::make_pair("purge", N_("Completely removing %s")),
00ec24d0
JF
54 std::make_pair("trigproc", N_("Running post-installation trigger %s"))
55 };
56
57 const std::pair<const char *, const char *> * const PackageProcessingOpsBegin = PackageProcessingOps;
58 const std::pair<const char *, const char *> * const PackageProcessingOpsEnd = PackageProcessingOps + sizeof(PackageProcessingOps) / sizeof(PackageProcessingOps[0]);
59
60 // Predicate to test whether an entry in the PackageProcessingOps
61 // array matches a string.
62 class MatchProcessingOp
63 {
64 const char *target;
65
66 public:
67 MatchProcessingOp(const char *the_target)
68 : target(the_target)
69 {
70 }
71
72 bool operator()(const std::pair<const char *, const char *> &pair) const
73 {
74 return strcmp(pair.first, target) == 0;
75 }
76 };
77}
78
0e5943eb
JF
79/* helper function to ionice the given PID
80
81 there is no C header for ionice yet - just the syscall interface
82 so we use the binary from util-linux
83*/
84static bool
85ionice(int PID)
86{
87 if (!FileExists("/usr/bin/ionice"))
88 return false;
89 pid_t Process = ExecFork();
90 if (Process == 0)
91 {
92 char buf[32];
93 snprintf(buf, sizeof(buf), "-p%d", PID);
94 const char *Args[4];
95 Args[0] = "/usr/bin/ionice";
96 Args[1] = "-c3";
97 Args[2] = buf;
98 Args[3] = 0;
99 execv(Args[0], (char **)Args);
100 }
101 return ExecWait(Process, "ionice");
102}
103
da6ee469
JF
104// DPkgPM::pkgDPkgPM - Constructor /*{{{*/
105// ---------------------------------------------------------------------
106/* */
00ec24d0
JF
107pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache)
108 : pkgPackageManager(Cache), dpkgbuf_pos(0),
109 term_out(NULL), PackagesDone(0), PackagesTotal(0)
da6ee469
JF
110{
111}
112 /*}}}*/
113// DPkgPM::pkgDPkgPM - Destructor /*{{{*/
114// ---------------------------------------------------------------------
115/* */
116pkgDPkgPM::~pkgDPkgPM()
117{
118}
119 /*}}}*/
120// DPkgPM::Install - Install a package /*{{{*/
121// ---------------------------------------------------------------------
122/* Add an install operation to the sequence list */
123bool pkgDPkgPM::Install(PkgIterator Pkg,string File)
124{
125 if (File.empty() == true || Pkg.end() == true)
126 return _error->Error("Internal Error, No file name for %s",Pkg.Name());
127
128 List.push_back(Item(Item::Install,Pkg,File));
129 return true;
130}
131 /*}}}*/
132// DPkgPM::Configure - Configure a package /*{{{*/
133// ---------------------------------------------------------------------
134/* Add a configure operation to the sequence list */
135bool pkgDPkgPM::Configure(PkgIterator Pkg)
136{
137 if (Pkg.end() == true)
138 return false;
0e5943eb
JF
139
140 List.push_back(Item(Item::Configure, Pkg));
141
142 // Use triggers for config calls if we configure "smart"
143 // as otherwise Pre-Depends will not be satisfied, see #526774
144 if (_config->FindB("DPkg::TriggersPending", false) == true)
145 List.push_back(Item(Item::TriggersPending, PkgIterator()));
146
da6ee469
JF
147 return true;
148}
149 /*}}}*/
150// DPkgPM::Remove - Remove a package /*{{{*/
151// ---------------------------------------------------------------------
152/* Add a remove operation to the sequence list */
153bool pkgDPkgPM::Remove(PkgIterator Pkg,bool Purge)
154{
155 if (Pkg.end() == true)
156 return false;
157
158 if (Purge == true)
159 List.push_back(Item(Item::Purge,Pkg));
160 else
161 List.push_back(Item(Item::Remove,Pkg));
162 return true;
163}
164 /*}}}*/
da6ee469
JF
165// DPkgPM::SendV2Pkgs - Send version 2 package info /*{{{*/
166// ---------------------------------------------------------------------
167/* This is part of the helper script communication interface, it sends
168 very complete information down to the other end of the pipe.*/
169bool pkgDPkgPM::SendV2Pkgs(FILE *F)
170{
171 fprintf(F,"VERSION 2\n");
172
173 /* Write out all of the configuration directives by walking the
174 configuration tree */
175 const Configuration::Item *Top = _config->Tree(0);
176 for (; Top != 0;)
177 {
178 if (Top->Value.empty() == false)
179 {
180 fprintf(F,"%s=%s\n",
181 QuoteString(Top->FullTag(),"=\"\n").c_str(),
182 QuoteString(Top->Value,"\n").c_str());
183 }
184
185 if (Top->Child != 0)
186 {
187 Top = Top->Child;
188 continue;
189 }
190
191 while (Top != 0 && Top->Next == 0)
192 Top = Top->Parent;
193 if (Top != 0)
194 Top = Top->Next;
195 }
196 fprintf(F,"\n");
197
198 // Write out the package actions in order.
199 for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
200 {
0e5943eb
JF
201 if(I->Pkg.end() == true)
202 continue;
203
da6ee469
JF
204 pkgDepCache::StateCache &S = Cache[I->Pkg];
205
206 fprintf(F,"%s ",I->Pkg.Name());
207 // Current version
208 if (I->Pkg->CurrentVer == 0)
209 fprintf(F,"- ");
210 else
211 fprintf(F,"%s ",I->Pkg.CurrentVer().VerStr());
212
213 // Show the compare operator
214 // Target version
215 if (S.InstallVer != 0)
216 {
217 int Comp = 2;
218 if (I->Pkg->CurrentVer != 0)
219 Comp = S.InstVerIter(Cache).CompareVer(I->Pkg.CurrentVer());
220 if (Comp < 0)
221 fprintf(F,"> ");
222 if (Comp == 0)
223 fprintf(F,"= ");
224 if (Comp > 0)
225 fprintf(F,"< ");
226 fprintf(F,"%s ",S.InstVerIter(Cache).VerStr());
227 }
228 else
229 fprintf(F,"> - ");
230
231 // Show the filename/operation
232 if (I->Op == Item::Install)
233 {
234 // No errors here..
235 if (I->File[0] != '/')
236 fprintf(F,"**ERROR**\n");
237 else
238 fprintf(F,"%s\n",I->File.c_str());
239 }
240 if (I->Op == Item::Configure)
241 fprintf(F,"**CONFIGURE**\n");
242 if (I->Op == Item::Remove ||
243 I->Op == Item::Purge)
244 fprintf(F,"**REMOVE**\n");
245
246 if (ferror(F) != 0)
247 return false;
248 }
249 return true;
250}
251 /*}}}*/
252// DPkgPM::RunScriptsWithPkgs - Run scripts with package names on stdin /*{{{*/
253// ---------------------------------------------------------------------
254/* This looks for a list of scripts to run from the configuration file
255 each one is run and is fed on standard input a list of all .deb files
256 that are due to be installed. */
257bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
258{
259 Configuration::Item const *Opts = _config->Tree(Cnf);
260 if (Opts == 0 || Opts->Child == 0)
261 return true;
262 Opts = Opts->Child;
263
264 unsigned int Count = 1;
265 for (; Opts != 0; Opts = Opts->Next, Count++)
266 {
267 if (Opts->Value.empty() == true)
268 continue;
269
270 // Determine the protocol version
271 string OptSec = Opts->Value;
272 string::size_type Pos;
273 if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0)
274 Pos = OptSec.length();
275 OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos);
276
277 unsigned int Version = _config->FindI(OptSec+"::Version",1);
278
279 // Create the pipes
280 int Pipes[2];
281 if (pipe(Pipes) != 0)
282 return _error->Errno("pipe","Failed to create IPC pipe to subprocess");
283 SetCloseExec(Pipes[0],true);
284 SetCloseExec(Pipes[1],true);
285
286 // Purified Fork for running the script
287 pid_t Process = ExecFork();
288 if (Process == 0)
289 {
290 // Setup the FDs
291 dup2(Pipes[0],STDIN_FILENO);
292 SetCloseExec(STDOUT_FILENO,false);
293 SetCloseExec(STDIN_FILENO,false);
294 SetCloseExec(STDERR_FILENO,false);
295
296 const char *Args[4];
297 Args[0] = "/bin/sh";
298 Args[1] = "-c";
299 Args[2] = Opts->Value.c_str();
300 Args[3] = 0;
301 execv(Args[0],(char **)Args);
302 _exit(100);
303 }
304 close(Pipes[0]);
305 FILE *F = fdopen(Pipes[1],"w");
306 if (F == 0)
307 return _error->Errno("fdopen","Faild to open new FD");
308
309 // Feed it the filenames.
310 bool Die = false;
311 if (Version <= 1)
312 {
313 for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
314 {
315 // Only deal with packages to be installed from .deb
316 if (I->Op != Item::Install)
317 continue;
318
319 // No errors here..
320 if (I->File[0] != '/')
321 continue;
322
323 /* Feed the filename of each package that is pending install
324 into the pipe. */
325 fprintf(F,"%s\n",I->File.c_str());
326 if (ferror(F) != 0)
327 {
328 Die = true;
329 break;
330 }
331 }
332 }
333 else
334 Die = !SendV2Pkgs(F);
335
336 fclose(F);
337
338 // Clean up the sub process
339 if (ExecWait(Process,Opts->Value.c_str()) == false)
340 return _error->Error("Failure running script %s",Opts->Value.c_str());
341 }
342
343 return true;
344}
00ec24d0
JF
345
346 /*}}}*/
347// DPkgPM::DoStdin - Read stdin and pass to slave pty /*{{{*/
348// ---------------------------------------------------------------------
349/*
350*/
351void pkgDPkgPM::DoStdin(int master)
352{
353 unsigned char input_buf[256] = {0,};
354 ssize_t len = read(0, input_buf, sizeof(input_buf));
355 if (len)
356 write(master, input_buf, len);
357 else
358 stdin_is_dev_null = true;
359}
360 /*}}}*/
361// DPkgPM::DoTerminalPty - Read the terminal pty and write log /*{{{*/
362// ---------------------------------------------------------------------
363/*
364 * read the terminal pty and write log
365 */
366void pkgDPkgPM::DoTerminalPty(int master)
367{
368 unsigned char term_buf[1024] = {0,0, };
369
370 ssize_t len=read(master, term_buf, sizeof(term_buf));
371 if(len == -1 && errno == EIO)
372 {
373 // this happens when the child is about to exit, we
374 // give it time to actually exit, otherwise we run
375 // into a race
376 usleep(500000);
377 return;
378 }
379 if(len <= 0)
380 return;
381 write(1, term_buf, len);
382 if(term_out)
383 fwrite(term_buf, len, sizeof(char), term_out);
384}
da6ee469 385 /*}}}*/
00ec24d0
JF
386// DPkgPM::ProcessDpkgStatusBuf /*{{{*/
387// ---------------------------------------------------------------------
388/*
389 */
390void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
391{
0e5943eb 392 bool const Debug = _config->FindB("Debug::pkgDPkgProgressReporting",false);
00ec24d0
JF
393 // the status we output
394 ostringstream status;
395
0e5943eb 396 if (Debug == true)
00ec24d0
JF
397 std::clog << "got from dpkg '" << line << "'" << std::endl;
398
399
400 /* dpkg sends strings like this:
401 'status: <pkg>: <pkg qstate>'
402 errors look like this:
403 'status: /var/cache/apt/archives/krecipes_0.8.1-0ubuntu1_i386.deb : error : trying to overwrite `/usr/share/doc/kde/HTML/en/krecipes/krectip.png', which is also in package krecipes-data
404 and conffile-prompt like this
405 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited
406
407 Newer versions of dpkg sent also:
408 'processing: install: pkg'
409 'processing: configure: pkg'
410 'processing: remove: pkg'
0e5943eb 411 'processing: purge: pkg' - but for apt is it a ignored "unknown" action
00ec24d0
JF
412 'processing: trigproc: trigger'
413
414 */
415 char* list[5];
416 // dpkg sends multiline error messages sometimes (see
417 // #374195 for a example. we should support this by
418 // either patching dpkg to not send multiline over the
419 // statusfd or by rewriting the code here to deal with
420 // it. for now we just ignore it and not crash
421 TokSplitString(':', line, list, sizeof(list)/sizeof(list[0]));
422 if( list[0] == NULL || list[1] == NULL || list[2] == NULL)
423 {
0e5943eb 424 if (Debug == true)
00ec24d0
JF
425 std::clog << "ignoring line: not enough ':'" << std::endl;
426 return;
427 }
0e5943eb
JF
428 const char* const pkg = list[1];
429 const char* action = _strstrip(list[2]);
00ec24d0
JF
430
431 // 'processing' from dpkg looks like
432 // 'processing: action: pkg'
433 if(strncmp(list[0], "processing", strlen("processing")) == 0)
434 {
435 char s[200];
0e5943eb
JF
436 const char* const pkg_or_trigger = _strstrip(list[2]);
437 action = _strstrip( list[1]);
00ec24d0
JF
438 const std::pair<const char *, const char *> * const iter =
439 std::find_if(PackageProcessingOpsBegin,
440 PackageProcessingOpsEnd,
441 MatchProcessingOp(action));
442 if(iter == PackageProcessingOpsEnd)
443 {
0e5943eb
JF
444 if (Debug == true)
445 std::clog << "ignoring unknown action: " << action << std::endl;
00ec24d0
JF
446 return;
447 }
448 snprintf(s, sizeof(s), _(iter->second), pkg_or_trigger);
449
450 status << "pmstatus:" << pkg_or_trigger
451 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
452 << ":" << s
453 << endl;
454 if(OutStatusFd > 0)
455 write(OutStatusFd, status.str().c_str(), status.str().size());
0e5943eb 456 if (Debug == true)
00ec24d0
JF
457 std::clog << "send: '" << status.str() << "'" << endl;
458 return;
459 }
460
461 if(strncmp(action,"error",strlen("error")) == 0)
462 {
463 status << "pmerror:" << list[1]
464 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
465 << ":" << list[3]
466 << endl;
467 if(OutStatusFd > 0)
468 write(OutStatusFd, status.str().c_str(), status.str().size());
0e5943eb 469 if (Debug == true)
00ec24d0
JF
470 std::clog << "send: '" << status.str() << "'" << endl;
471 return;
472 }
0e5943eb 473 else if(strncmp(action,"conffile",strlen("conffile")) == 0)
00ec24d0
JF
474 {
475 status << "pmconffile:" << list[1]
476 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
477 << ":" << list[3]
478 << endl;
479 if(OutStatusFd > 0)
480 write(OutStatusFd, status.str().c_str(), status.str().size());
0e5943eb 481 if (Debug == true)
00ec24d0
JF
482 std::clog << "send: '" << status.str() << "'" << endl;
483 return;
484 }
485
0e5943eb 486 vector<struct DpkgState> const &states = PackageOps[pkg];
00ec24d0
JF
487 const char *next_action = NULL;
488 if(PackageOpsDone[pkg] < states.size())
489 next_action = states[PackageOpsDone[pkg]].state;
490 // check if the package moved to the next dpkg state
491 if(next_action && (strcmp(action, next_action) == 0))
492 {
493 // only read the translation if there is actually a next
494 // action
495 const char *translation = _(states[PackageOpsDone[pkg]].str);
496 char s[200];
497 snprintf(s, sizeof(s), translation, pkg);
498
499 // we moved from one dpkg state to a new one, report that
500 PackageOpsDone[pkg]++;
501 PackagesDone++;
502 // build the status str
503 status << "pmstatus:" << pkg
504 << ":" << (PackagesDone/float(PackagesTotal)*100.0)
505 << ":" << s
506 << endl;
507 if(OutStatusFd > 0)
508 write(OutStatusFd, status.str().c_str(), status.str().size());
0e5943eb 509 if (Debug == true)
00ec24d0
JF
510 std::clog << "send: '" << status.str() << "'" << endl;
511 }
0e5943eb 512 if (Debug == true)
00ec24d0
JF
513 std::clog << "(parsed from dpkg) pkg: " << pkg
514 << " action: " << action << endl;
515}
0e5943eb
JF
516 /*}}}*/
517// DPkgPM::DoDpkgStatusFd /*{{{*/
00ec24d0
JF
518// ---------------------------------------------------------------------
519/*
520 */
521void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd)
522{
523 char *p, *q;
524 int len;
525
526 len=read(statusfd, &dpkgbuf[dpkgbuf_pos], sizeof(dpkgbuf)-dpkgbuf_pos);
527 dpkgbuf_pos += len;
528 if(len <= 0)
529 return;
530
531 // process line by line if we have a buffer
532 p = q = dpkgbuf;
533 while((q=(char*)memchr(p, '\n', dpkgbuf+dpkgbuf_pos-p)) != NULL)
534 {
535 *q = 0;
536 ProcessDpkgStatusLine(OutStatusFd, p);
537 p=q+1; // continue with next line
538 }
539
540 // now move the unprocessed bits (after the final \n that is now a 0x0)
541 // to the start and update dpkgbuf_pos
542 void *memrchr(void const *, int, size_t);
543 p = (char*)memrchr(dpkgbuf, 0, dpkgbuf_pos);
544 if(p == NULL)
545 return;
546
547 // we are interessted in the first char *after* 0x0
548 p++;
549
550 // move the unprocessed tail to the start and update pos
551 memmove(dpkgbuf, p, p-dpkgbuf);
552 dpkgbuf_pos = dpkgbuf+dpkgbuf_pos-p;
553}
554 /*}}}*/
0e5943eb 555// DPkgPM::OpenLog /*{{{*/
00ec24d0
JF
556bool pkgDPkgPM::OpenLog()
557{
558 string logdir = _config->FindDir("Dir::Log");
559 if(not FileExists(logdir))
560 return _error->Error(_("Directory '%s' missing"), logdir.c_str());
561 string logfile_name = flCombine(logdir,
562 _config->Find("Dir::Log::Terminal"));
563 if (!logfile_name.empty())
564 {
565 term_out = fopen(logfile_name.c_str(),"a");
0e5943eb
JF
566 if (term_out == NULL)
567 return _error->WarningE(_("Could not open file '%s'"), logfile_name.c_str());
568
00ec24d0
JF
569 chmod(logfile_name.c_str(), 0600);
570 // output current time
571 char outstr[200];
572 time_t t = time(NULL);
573 struct tm *tmp = localtime(&t);
574 strftime(outstr, sizeof(outstr), "%F %T", tmp);
0e5943eb 575 fprintf(term_out, "\nLog started: %s\n", outstr);
00ec24d0
JF
576 }
577 return true;
578}
0e5943eb
JF
579 /*}}}*/
580// DPkg::CloseLog /*{{{*/
00ec24d0
JF
581bool pkgDPkgPM::CloseLog()
582{
583 if(term_out)
584 {
585 char outstr[200];
586 time_t t = time(NULL);
587 struct tm *tmp = localtime(&t);
588 strftime(outstr, sizeof(outstr), "%F %T", tmp);
589 fprintf(term_out, "Log ended: ");
590 fprintf(term_out, "%s", outstr);
591 fprintf(term_out, "\n");
592 fclose(term_out);
593 }
594 term_out = NULL;
595 return true;
596}
0e5943eb 597 /*}}}*/
00ec24d0
JF
598/*{{{*/
599// This implements a racy version of pselect for those architectures
600// that don't have a working implementation.
601// FIXME: Probably can be removed on Lenny+1
602static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds,
603 fd_set *exceptfds, const struct timespec *timeout,
604 const sigset_t *sigmask)
605{
606 sigset_t origmask;
607 struct timeval tv;
608 int retval;
609
610 tv.tv_sec = timeout->tv_sec;
611 tv.tv_usec = timeout->tv_nsec/1000;
612
613 sigprocmask(SIG_SETMASK, sigmask, &origmask);
614 retval = select(nfds, readfds, writefds, exceptfds, &tv);
615 sigprocmask(SIG_SETMASK, &origmask, 0);
616 return retval;
617}
618/*}}}*/
da6ee469
JF
619// DPkgPM::Go - Run the sequence /*{{{*/
620// ---------------------------------------------------------------------
621/* This globs the operations and calls dpkg
622 *
623 * If it is called with "OutStatusFd" set to a valid file descriptor
624 * apt will report the install progress over this fd. It maps the
625 * dpkg states a package goes through to human readable (and i10n-able)
626 * names and calculates a percentage for each step.
627*/
628bool pkgDPkgPM::Go(int OutStatusFd)
629{
0e5943eb
JF
630 fd_set rfds;
631 struct timespec tv;
632 sigset_t sigmask;
633 sigset_t original_sigmask;
634
635 unsigned int const MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024);
636 unsigned int const MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024);
637 bool const NoTriggers = _config->FindB("DPkg::NoTriggers", false);
da6ee469
JF
638
639 if (RunScripts("DPkg::Pre-Invoke") == false)
640 return false;
641
642 if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false)
643 return false;
00ec24d0 644
0e5943eb
JF
645 // support subpressing of triggers processing for special
646 // cases like d-i that runs the triggers handling manually
647 bool const SmartConf = (_config->Find("PackageManager::Configure", "all") != "all");
648 bool const TriggersPending = _config->FindB("DPkg::TriggersPending", false);
649 if (_config->FindB("DPkg::ConfigurePending", SmartConf) == true)
650 List.push_back(Item(Item::ConfigurePending, PkgIterator()));
651
da6ee469
JF
652 // map the dpkg states to the operations that are performed
653 // (this is sorted in the same way as Item::Ops)
00ec24d0 654 static const struct DpkgState DpkgStatesOpMap[][7] = {
da6ee469
JF
655 // Install operation
656 {
657 {"half-installed", N_("Preparing %s")},
658 {"unpacked", N_("Unpacking %s") },
659 {NULL, NULL}
660 },
661 // Configure operation
662 {
663 {"unpacked",N_("Preparing to configure %s") },
664 {"half-configured", N_("Configuring %s") },
665 { "installed", N_("Installed %s")},
666 {NULL, NULL}
667 },
668 // Remove operation
669 {
670 {"half-configured", N_("Preparing for removal of %s")},
671 {"half-installed", N_("Removing %s")},
672 {"config-files", N_("Removed %s")},
673 {NULL, NULL}
674 },
675 // Purge operation
676 {
677 {"config-files", N_("Preparing to completely remove %s")},
678 {"not-installed", N_("Completely removed %s")},
679 {NULL, NULL}
680 },
681 };
682
da6ee469
JF
683 // init the PackageOps map, go over the list of packages that
684 // that will be [installed|configured|removed|purged] and add
685 // them to the PackageOps map (the dpkg states it goes through)
686 // and the PackageOpsTranslations (human readable strings)
0e5943eb 687 for (vector<Item>::const_iterator I = List.begin(); I != List.end();I++)
da6ee469 688 {
0e5943eb
JF
689 if((*I).Pkg.end() == true)
690 continue;
691
692 string const name = (*I).Pkg.Name();
da6ee469
JF
693 PackageOpsDone[name] = 0;
694 for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; i++)
695 {
696 PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]);
00ec24d0 697 PackagesTotal++;
da6ee469 698 }
0e5943eb 699 }
da6ee469 700
00ec24d0
JF
701 stdin_is_dev_null = false;
702
703 // create log
704 OpenLog();
705
da6ee469 706 // this loop is runs once per operation
0e5943eb 707 for (vector<Item>::const_iterator I = List.begin(); I != List.end();)
da6ee469 708 {
0e5943eb
JF
709 // Do all actions with the same Op in one run
710 vector<Item>::const_iterator J = I;
711 if (TriggersPending == true)
712 for (; J != List.end(); J++)
713 {
714 if (J->Op == I->Op)
715 continue;
716 if (J->Op != Item::TriggersPending)
717 break;
718 vector<Item>::const_iterator T = J + 1;
719 if (T != List.end() && T->Op == I->Op)
720 continue;
721 break;
722 }
723 else
724 for (; J != List.end() && J->Op == I->Op; J++)
725 /* nothing */;
da6ee469
JF
726
727 // Generate the argument list
728 const char *Args[MaxArgs + 50];
0e5943eb
JF
729
730 // Now check if we are within the MaxArgs limit
731 //
732 // this code below is problematic, because it may happen that
733 // the argument list is split in a way that A depends on B
734 // and they are in the same "--configure A B" run
735 // - with the split they may now be configured in different
736 // runs
da6ee469
JF
737 if (J - I > (signed)MaxArgs)
738 J = I + MaxArgs;
739
740 unsigned int n = 0;
741 unsigned long Size = 0;
0e5943eb 742 string const Tmp = _config->Find("Dir::Bin::dpkg","dpkg");
da6ee469
JF
743 Args[n++] = Tmp.c_str();
744 Size += strlen(Args[n-1]);
745
746 // Stick in any custom dpkg options
747 Configuration::Item const *Opts = _config->Tree("DPkg::Options");
748 if (Opts != 0)
749 {
750 Opts = Opts->Child;
751 for (; Opts != 0; Opts = Opts->Next)
752 {
753 if (Opts->Value.empty() == true)
754 continue;
755 Args[n++] = Opts->Value.c_str();
756 Size += Opts->Value.length();
757 }
758 }
759
760 char status_fd_buf[20];
761 int fd[2];
762 pipe(fd);
763
764 Args[n++] = "--status-fd";
765 Size += strlen(Args[n-1]);
766 snprintf(status_fd_buf,sizeof(status_fd_buf),"%i", fd[1]);
767 Args[n++] = status_fd_buf;
768 Size += strlen(Args[n-1]);
769
770 switch (I->Op)
771 {
772 case Item::Remove:
773 Args[n++] = "--force-depends";
774 Size += strlen(Args[n-1]);
7ae8af64
JF
775 Args[n++] = "--force-remove-reinstreq";
776 Size += strlen(Args[n-1]);
da6ee469
JF
777 Args[n++] = "--force-remove-essential";
778 Size += strlen(Args[n-1]);
779 Args[n++] = "--remove";
780 Size += strlen(Args[n-1]);
781 break;
782
783 case Item::Purge:
784 Args[n++] = "--force-depends";
785 Size += strlen(Args[n-1]);
7ae8af64
JF
786 Args[n++] = "--force-remove-reinstreq";
787 Size += strlen(Args[n-1]);
da6ee469
JF
788 Args[n++] = "--force-remove-essential";
789 Size += strlen(Args[n-1]);
790 Args[n++] = "--purge";
791 Size += strlen(Args[n-1]);
792 break;
793
794 case Item::Configure:
795 Args[n++] = "--configure";
796 Size += strlen(Args[n-1]);
797 break;
0e5943eb
JF
798
799 case Item::ConfigurePending:
800 Args[n++] = "--configure";
801 Size += strlen(Args[n-1]);
802 Args[n++] = "--pending";
803 Size += strlen(Args[n-1]);
804 break;
805
806 case Item::TriggersPending:
807 Args[n++] = "--triggers-only";
808 Size += strlen(Args[n-1]);
809 Args[n++] = "--pending";
810 Size += strlen(Args[n-1]);
811 break;
812
da6ee469
JF
813 case Item::Install:
814 Args[n++] = "--unpack";
815 Size += strlen(Args[n-1]);
00ec24d0
JF
816 Args[n++] = "--auto-deconfigure";
817 Size += strlen(Args[n-1]);
da6ee469
JF
818 break;
819 }
0e5943eb
JF
820
821 if (NoTriggers == true && I->Op != Item::TriggersPending &&
822 I->Op != Item::ConfigurePending)
823 {
824 Args[n++] = "--no-triggers";
825 Size += strlen(Args[n-1]);
826 }
827
da6ee469
JF
828 // Write in the file or package names
829 if (I->Op == Item::Install)
830 {
831 for (;I != J && Size < MaxArgBytes; I++)
832 {
833 if (I->File[0] != '/')
834 return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
835 Args[n++] = I->File.c_str();
836 Size += strlen(Args[n-1]);
837 }
838 }
839 else
840 {
841 for (;I != J && Size < MaxArgBytes; I++)
842 {
0e5943eb
JF
843 if((*I).Pkg.end() == true)
844 continue;
da6ee469
JF
845 Args[n++] = I->Pkg.Name();
846 Size += strlen(Args[n-1]);
847 }
848 }
849 Args[n] = 0;
850 J = I;
851
852 if (_config->FindB("Debug::pkgDPkgPM",false) == true)
853 {
854 for (unsigned int k = 0; k != n; k++)
855 clog << Args[k] << ' ';
856 clog << endl;
857 continue;
858 }
859
860 cout << flush;
861 clog << flush;
862 cerr << flush;
863
864 typedef void (*sighandler_t)(int);
865
866 /* Mask off sig int/quit. We do this because dpkg also does when
867 it forks scripts. What happens is that when you hit ctrl-c it sends
868 it to all processes in the group. Since dpkg ignores the signal
869 it doesn't die but we do! So we must also ignore it */
870 sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN);
871 sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN);
00ec24d0
JF
872
873 // ignore SIGHUP as well (debian #463030)
874 sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN);
875
876 struct termios tt;
00ec24d0 877 struct winsize win;
0e5943eb
JF
878 int master = -1;
879 int slave = -1;
880
881 // if tcgetattr does not return zero there was a error
882 // and we do not do any pty magic
883 if (tcgetattr(0, &tt) == 0)
00ec24d0 884 {
0e5943eb
JF
885 ioctl(0, TIOCGWINSZ, (char *)&win);
886 if (openpty(&master, &slave, NULL, &tt, &win) < 0)
887 {
888 const char *s = _("Can not write log, openpty() "
889 "failed (/dev/pts not mounted?)\n");
890 fprintf(stderr, "%s",s);
891 if(term_out)
892 fprintf(term_out, "%s",s);
893 master = slave = -1;
894 } else {
895 struct termios rtt;
896 rtt = tt;
897 cfmakeraw(&rtt);
898 rtt.c_lflag &= ~ECHO;
899 // block SIGTTOU during tcsetattr to prevent a hang if
900 // the process is a member of the background process group
901 // http://www.opengroup.org/onlinepubs/000095399/functions/tcsetattr.html
902 sigemptyset(&sigmask);
903 sigaddset(&sigmask, SIGTTOU);
904 sigprocmask(SIG_BLOCK,&sigmask, &original_sigmask);
905 tcsetattr(0, TCSAFLUSH, &rtt);
906 sigprocmask(SIG_SETMASK, &original_sigmask, 0);
907 }
00ec24d0
JF
908 }
909
da6ee469
JF
910 // Fork dpkg
911 pid_t Child;
912 _config->Set("APT::Keep-Fds::",fd[1]);
0e5943eb
JF
913 // send status information that we are about to fork dpkg
914 if(OutStatusFd > 0) {
915 ostringstream status;
916 status << "pmstatus:dpkg-exec:"
917 << (PackagesDone/float(PackagesTotal)*100.0)
918 << ":" << _("Running dpkg")
919 << endl;
920 write(OutStatusFd, status.str().c_str(), status.str().size());
921 }
da6ee469
JF
922 Child = ExecFork();
923
924 // This is the child
925 if (Child == 0)
926 {
00ec24d0
JF
927 if(slave >= 0 && master >= 0)
928 {
929 setsid();
930 ioctl(slave, TIOCSCTTY, 0);
931 close(master);
932 dup2(slave, 0);
933 dup2(slave, 1);
934 dup2(slave, 2);
935 close(slave);
936 }
da6ee469 937 close(fd[0]); // close the read end of the pipe
00ec24d0 938
0e5943eb
JF
939 if (_config->FindDir("DPkg::Chroot-Directory","/") != "/")
940 {
941 std::cerr << "Chrooting into "
942 << _config->FindDir("DPkg::Chroot-Directory")
943 << std::endl;
944 if (chroot(_config->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
945 _exit(100);
946 }
947
da6ee469
JF
948 if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
949 _exit(100);
950
951 if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO))
952 {
953 int Flags,dummy;
954 if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
955 _exit(100);
956
957 // Discard everything in stdin before forking dpkg
958 if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
959 _exit(100);
960
961 while (read(STDIN_FILENO,&dummy,1) == 1);
962
963 if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
964 _exit(100);
965 }
00ec24d0 966
da6ee469
JF
967 /* No Job Control Stop Env is a magic dpkg var that prevents it
968 from using sigstop */
00ec24d0 969 putenv((char *)"DPKG_NO_TSTP=yes");
da6ee469
JF
970 execvp(Args[0],(char **)Args);
971 cerr << "Could not exec dpkg!" << endl;
972 _exit(100);
973 }
974
0e5943eb
JF
975 // apply ionice
976 if (_config->FindB("DPkg::UseIoNice", false) == true)
977 ionice(Child);
978
da6ee469
JF
979 // clear the Keep-Fd again
980 _config->Clear("APT::Keep-Fds",fd[1]);
981
982 // Wait for dpkg
983 int Status = 0;
984
985 // we read from dpkg here
0e5943eb 986 int const _dpkgin = fd[0];
da6ee469
JF
987 close(fd[1]); // close the write end of the pipe
988
00ec24d0
JF
989 if(slave > 0)
990 close(slave);
991
992 // setups fds
00ec24d0
JF
993 sigemptyset(&sigmask);
994 sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask);
da6ee469 995
0e5943eb
JF
996 // the result of the waitpid call
997 int res;
00ec24d0 998 int select_ret;
da6ee469
JF
999 while ((res=waitpid(Child,&Status, WNOHANG)) != Child) {
1000 if(res < 0) {
1001 // FIXME: move this to a function or something, looks ugly here
1002 // error handling, waitpid returned -1
1003 if (errno == EINTR)
1004 continue;
1005 RunScripts("DPkg::Post-Invoke");
1006
1007 // Restore sig int/quit
1008 signal(SIGQUIT,old_SIGQUIT);
1009 signal(SIGINT,old_SIGINT);
00ec24d0 1010 signal(SIGHUP,old_SIGHUP);
da6ee469
JF
1011 return _error->Errno("waitpid","Couldn't wait for subprocess");
1012 }
da6ee469 1013
00ec24d0
JF
1014 // wait for input or output here
1015 FD_ZERO(&rfds);
1016 if (!stdin_is_dev_null)
1017 FD_SET(0, &rfds);
1018 FD_SET(_dpkgin, &rfds);
1019 if(master >= 0)
1020 FD_SET(master, &rfds);
1021 tv.tv_sec = 1;
1022 tv.tv_nsec = 0;
1023 select_ret = pselect(max(master, _dpkgin)+1, &rfds, NULL, NULL,
1024 &tv, &original_sigmask);
1025 if (select_ret < 0 && (errno == EINVAL || errno == ENOSYS))
1026 select_ret = racy_pselect(max(master, _dpkgin)+1, &rfds, NULL,
1027 NULL, &tv, &original_sigmask);
1028 if (select_ret == 0)
1029 continue;
1030 else if (select_ret < 0 && errno == EINTR)
1031 continue;
1032 else if (select_ret < 0)
1033 {
1034 perror("select() returned error");
1035 continue;
1036 }
da6ee469 1037
00ec24d0
JF
1038 if(master >= 0 && FD_ISSET(master, &rfds))
1039 DoTerminalPty(master);
1040 if(master >= 0 && FD_ISSET(0, &rfds))
1041 DoStdin(master);
1042 if(FD_ISSET(_dpkgin, &rfds))
1043 DoDpkgStatusFd(_dpkgin, OutStatusFd);
da6ee469
JF
1044 }
1045 close(_dpkgin);
1046
1047 // Restore sig int/quit
1048 signal(SIGQUIT,old_SIGQUIT);
1049 signal(SIGINT,old_SIGINT);
00ec24d0
JF
1050 signal(SIGHUP,old_SIGHUP);
1051
1052 if(master >= 0)
1053 {
1054 tcsetattr(0, TCSAFLUSH, &tt);
1055 close(master);
1056 }
da6ee469
JF
1057
1058 // Check for an error code.
1059 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
1060 {
1061 // if it was set to "keep-dpkg-runing" then we won't return
1062 // here but keep the loop going and just report it as a error
1063 // for later
0e5943eb 1064 bool const stopOnError = _config->FindB("Dpkg::StopOnError",true);
da6ee469
JF
1065
1066 if(stopOnError)
1067 RunScripts("DPkg::Post-Invoke");
1068
1069 if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
1070 _error->Error("Sub-process %s received a segmentation fault.",Args[0]);
1071 else if (WIFEXITED(Status) != 0)
1072 _error->Error("Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status));
1073 else
1074 _error->Error("Sub-process %s exited unexpectedly",Args[0]);
1075
00ec24d0
JF
1076 if(stopOnError)
1077 {
1078 CloseLog();
da6ee469 1079 return false;
00ec24d0 1080 }
da6ee469
JF
1081 }
1082 }
00ec24d0 1083 CloseLog();
da6ee469
JF
1084
1085 if (RunScripts("DPkg::Post-Invoke") == false)
1086 return false;
00ec24d0
JF
1087
1088 Cache.writeStateFile(NULL);
da6ee469
JF
1089 return true;
1090}
1091 /*}}}*/
1092// pkgDpkgPM::Reset - Dump the contents of the command list /*{{{*/
1093// ---------------------------------------------------------------------
1094/* */
1095void pkgDPkgPM::Reset()
1096{
1097 List.erase(List.begin(),List.end());
1098}
1099 /*}}}*/
00ec24d0
JF
1100
1101/* memrchr -- find the last occurrence of a byte in a memory block
1102
1103 Copyright (C) 1991, 1993, 1996, 1997, 1999, 2000, 2003, 2004, 2005,
1104 2006, 2007, 2008 Free Software Foundation, Inc.
1105
1106 Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
1107 with help from Dan Sahlin (dan@sics.se) and
1108 commentary by Jim Blandy (jimb@ai.mit.edu);
1109 adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
1110 and implemented by Roland McGrath (roland@ai.mit.edu).
1111
1112 This program is free software: you can redistribute it and/or modify
1113 it under the terms of the GNU General Public License as published by
1114 the Free Software Foundation; either version 3 of the License, or
1115 (at your option) any later version.
1116
1117 This program is distributed in the hope that it will be useful,
1118 but WITHOUT ANY WARRANTY; without even the implied warranty of
1119 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1120 GNU General Public License for more details.
1121
1122 You should have received a copy of the GNU General Public License
1123 along with this program. If not, see <http://www.gnu.org/licenses/>. */
1124
1125#if defined _LIBC
1126# include <memcopy.h>
1127#else
1128# include <config.h>
1129# define reg_char char
1130#endif
1131
1132#include <string.h>
1133#include <limits.h>
1134
1135#undef __memrchr
1136#ifdef _LIBC
1137# undef memrchr
1138#endif
1139
1140#ifndef weak_alias
1141# define __memrchr memrchr
1142#endif
1143
1144/* Search no more than N bytes of S for C. */
1145void *
1146__memrchr (void const *s, int c_in, size_t n)
1147{
1148 /* On 32-bit hardware, choosing longword to be a 32-bit unsigned
1149 long instead of a 64-bit uintmax_t tends to give better
1150 performance. On 64-bit hardware, unsigned long is generally 64
1151 bits already. Change this typedef to experiment with
1152 performance. */
1153 typedef unsigned long int longword;
1154
1155 const unsigned char *char_ptr;
1156 const longword *longword_ptr;
1157 longword repeated_one;
1158 longword repeated_c;
1159 unsigned reg_char c;
1160
1161 c = (unsigned char) c_in;
1162
1163 /* Handle the last few bytes by reading one byte at a time.
1164 Do this until CHAR_PTR is aligned on a longword boundary. */
1165 for (char_ptr = (const unsigned char *) s + n;
1166 n > 0 && (size_t) char_ptr % sizeof (longword) != 0;
1167 --n)
1168 if (*--char_ptr == c)
1169 return (void *) char_ptr;
1170
1171 longword_ptr = (const longword *) char_ptr;
1172
1173 /* All these elucidatory comments refer to 4-byte longwords,
1174 but the theory applies equally well to any size longwords. */
1175
1176 /* Compute auxiliary longword values:
1177 repeated_one is a value which has a 1 in every byte.
1178 repeated_c has c in every byte. */
1179 repeated_one = 0x01010101;
1180 repeated_c = c | (c << 8);
1181 repeated_c |= repeated_c << 16;
1182 if (0xffffffffU < (longword) -1)
1183 {
1184 repeated_one |= repeated_one << 31 << 1;
1185 repeated_c |= repeated_c << 31 << 1;
1186 if (8 < sizeof (longword))
1187 {
1188 size_t i;
1189
1190 for (i = 64; i < sizeof (longword) * 8; i *= 2)
1191 {
1192 repeated_one |= repeated_one << i;
1193 repeated_c |= repeated_c << i;
1194 }
1195 }
1196 }
1197
1198 /* Instead of the traditional loop which tests each byte, we will test a
1199 longword at a time. The tricky part is testing if *any of the four*
1200 bytes in the longword in question are equal to c. We first use an xor
1201 with repeated_c. This reduces the task to testing whether *any of the
1202 four* bytes in longword1 is zero.
1203
1204 We compute tmp =
1205 ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
1206 That is, we perform the following operations:
1207 1. Subtract repeated_one.
1208 2. & ~longword1.
1209 3. & a mask consisting of 0x80 in every byte.
1210 Consider what happens in each byte:
1211 - If a byte of longword1 is zero, step 1 and 2 transform it into 0xff,
1212 and step 3 transforms it into 0x80. A carry can also be propagated
1213 to more significant bytes.
1214 - If a byte of longword1 is nonzero, let its lowest 1 bit be at
1215 position k (0 <= k <= 7); so the lowest k bits are 0. After step 1,
1216 the byte ends in a single bit of value 0 and k bits of value 1.
1217 After step 2, the result is just k bits of value 1: 2^k - 1. After
1218 step 3, the result is 0. And no carry is produced.
1219 So, if longword1 has only non-zero bytes, tmp is zero.
1220 Whereas if longword1 has a zero byte, call j the position of the least
1221 significant zero byte. Then the result has a zero at positions 0, ...,
1222 j-1 and a 0x80 at position j. We cannot predict the result at the more
1223 significant bytes (positions j+1..3), but it does not matter since we
1224 already have a non-zero bit at position 8*j+7.
1225
1226 So, the test whether any byte in longword1 is zero is equivalent to
1227 testing whether tmp is nonzero. */
1228
1229 while (n >= sizeof (longword))
1230 {
1231 longword longword1 = *--longword_ptr ^ repeated_c;
1232
1233 if ((((longword1 - repeated_one) & ~longword1)
1234 & (repeated_one << 7)) != 0)
1235 {
1236 longword_ptr++;
1237 break;
1238 }
1239 n -= sizeof (longword);
1240 }
1241
1242 char_ptr = (const unsigned char *) longword_ptr;
1243
1244 /* At this point, we know that either n < sizeof (longword), or one of the
1245 sizeof (longword) bytes starting at char_ptr is == c. On little-endian
1246 machines, we could determine the first such byte without any further
1247 memory accesses, just by looking at the tmp result from the last loop
1248 iteration. But this does not work on big-endian machines. Choose code
1249 that works in both cases. */
1250
1251 while (n-- > 0)
1252 {
1253 if (*--char_ptr == c)
1254 return (void *) char_ptr;
1255 }
1256
1257 return NULL;
1258}
1259#ifdef weak_alias
1260weak_alias (__memrchr, memrchr)
1261#endif