]> git.saurik.com Git - apt.git/blame - apt-pkg/deb/dpkgpm.cc
* apt-pkg/deb/dpkgpm.cc, apt-pkg/contrib/fileutl.{cc,h}:
[apt.git] / apt-pkg / deb / dpkgpm.cc
CommitLineData
c0c0b100 1// -*- mode: cpp; mode: fold -*-
03e39e59 2// Description /*{{{*/
7f9a6360 3// $Id: dpkgpm.cc,v 1.28 2004/01/27 02:25:01 mdz Exp $
03e39e59
AL
4/* ######################################################################
5
6 DPKG Package Manager - Provide an interface to dpkg
7
8 ##################################################################### */
9 /*}}}*/
10// Includes /*{{{*/
11#ifdef __GNUG__
12#pragma implementation "apt-pkg/dpkgpm.h"
13#endif
14#include <apt-pkg/dpkgpm.h>
15#include <apt-pkg/error.h>
16#include <apt-pkg/configuration.h>
b2e465d6
AL
17#include <apt-pkg/depcache.h>
18#include <apt-pkg/strutl.h>
614adaa0 19#include <apt-pkg/fileutl.h>
233b185f 20
03e39e59
AL
21#include <unistd.h>
22#include <stdlib.h>
23#include <fcntl.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26#include <signal.h>
27#include <errno.h>
db0c350f 28#include <stdio.h>
75ef8f14
MV
29#include <sstream>
30#include <map>
31
32#include <config.h>
33#include <apti18n.h>
b0ebdef5 34 /*}}}*/
233b185f
AL
35
36using namespace std;
03e39e59
AL
37
38// DPkgPM::pkgDPkgPM - Constructor /*{{{*/
39// ---------------------------------------------------------------------
40/* */
b2e465d6 41pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) : pkgPackageManager(Cache)
03e39e59
AL
42{
43}
44 /*}}}*/
45// DPkgPM::pkgDPkgPM - Destructor /*{{{*/
46// ---------------------------------------------------------------------
47/* */
48pkgDPkgPM::~pkgDPkgPM()
49{
50}
51 /*}}}*/
52// DPkgPM::Install - Install a package /*{{{*/
53// ---------------------------------------------------------------------
54/* Add an install operation to the sequence list */
55bool pkgDPkgPM::Install(PkgIterator Pkg,string File)
56{
57 if (File.empty() == true || Pkg.end() == true)
58 return _error->Error("Internal Error, No file name for %s",Pkg.Name());
59
60 List.push_back(Item(Item::Install,Pkg,File));
61 return true;
62}
63 /*}}}*/
64// DPkgPM::Configure - Configure a package /*{{{*/
65// ---------------------------------------------------------------------
66/* Add a configure operation to the sequence list */
67bool pkgDPkgPM::Configure(PkgIterator Pkg)
68{
69 if (Pkg.end() == true)
70 return false;
71
72 List.push_back(Item(Item::Configure,Pkg));
73 return true;
74}
75 /*}}}*/
76// DPkgPM::Remove - Remove a package /*{{{*/
77// ---------------------------------------------------------------------
78/* Add a remove operation to the sequence list */
fc4b5c9f 79bool pkgDPkgPM::Remove(PkgIterator Pkg,bool Purge)
03e39e59
AL
80{
81 if (Pkg.end() == true)
82 return false;
83
fc4b5c9f
AL
84 if (Purge == true)
85 List.push_back(Item(Item::Purge,Pkg));
86 else
87 List.push_back(Item(Item::Remove,Pkg));
6dd55be7
AL
88 return true;
89}
90 /*}}}*/
91// DPkgPM::RunScripts - Run a set of scripts /*{{{*/
92// ---------------------------------------------------------------------
93/* This looks for a list of script sto run from the configuration file,
94 each one is run with system from a forked child. */
95bool pkgDPkgPM::RunScripts(const char *Cnf)
96{
614adaa0 97 RunScripts(Cnf);
03e39e59 98}
db0c350f 99 /*}}}*/
b2e465d6
AL
100// DPkgPM::SendV2Pkgs - Send version 2 package info /*{{{*/
101// ---------------------------------------------------------------------
102/* This is part of the helper script communication interface, it sends
103 very complete information down to the other end of the pipe.*/
104bool pkgDPkgPM::SendV2Pkgs(FILE *F)
105{
106 fprintf(F,"VERSION 2\n");
107
108 /* Write out all of the configuration directives by walking the
109 configuration tree */
110 const Configuration::Item *Top = _config->Tree(0);
111 for (; Top != 0;)
112 {
113 if (Top->Value.empty() == false)
114 {
115 fprintf(F,"%s=%s\n",
116 QuoteString(Top->FullTag(),"=\"\n").c_str(),
117 QuoteString(Top->Value,"\n").c_str());
118 }
119
120 if (Top->Child != 0)
121 {
122 Top = Top->Child;
123 continue;
124 }
125
126 while (Top != 0 && Top->Next == 0)
127 Top = Top->Parent;
128 if (Top != 0)
129 Top = Top->Next;
130 }
131 fprintf(F,"\n");
132
133 // Write out the package actions in order.
134 for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
135 {
136 pkgDepCache::StateCache &S = Cache[I->Pkg];
137
138 fprintf(F,"%s ",I->Pkg.Name());
139 // Current version
140 if (I->Pkg->CurrentVer == 0)
141 fprintf(F,"- ");
142 else
143 fprintf(F,"%s ",I->Pkg.CurrentVer().VerStr());
144
145 // Show the compare operator
146 // Target version
147 if (S.InstallVer != 0)
148 {
149 int Comp = 2;
150 if (I->Pkg->CurrentVer != 0)
151 Comp = S.InstVerIter(Cache).CompareVer(I->Pkg.CurrentVer());
152 if (Comp < 0)
153 fprintf(F,"> ");
154 if (Comp == 0)
155 fprintf(F,"= ");
156 if (Comp > 0)
157 fprintf(F,"< ");
158 fprintf(F,"%s ",S.InstVerIter(Cache).VerStr());
159 }
160 else
161 fprintf(F,"> - ");
162
163 // Show the filename/operation
164 if (I->Op == Item::Install)
165 {
166 // No errors here..
167 if (I->File[0] != '/')
168 fprintf(F,"**ERROR**\n");
169 else
170 fprintf(F,"%s\n",I->File.c_str());
171 }
172 if (I->Op == Item::Configure)
173 fprintf(F,"**CONFIGURE**\n");
174 if (I->Op == Item::Remove ||
175 I->Op == Item::Purge)
176 fprintf(F,"**REMOVE**\n");
177
178 if (ferror(F) != 0)
179 return false;
180 }
181 return true;
182}
183 /*}}}*/
db0c350f
AL
184// DPkgPM::RunScriptsWithPkgs - Run scripts with package names on stdin /*{{{*/
185// ---------------------------------------------------------------------
186/* This looks for a list of scripts to run from the configuration file
187 each one is run and is fed on standard input a list of all .deb files
188 that are due to be installed. */
189bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
190{
191 Configuration::Item const *Opts = _config->Tree(Cnf);
192 if (Opts == 0 || Opts->Child == 0)
193 return true;
194 Opts = Opts->Child;
195
196 unsigned int Count = 1;
197 for (; Opts != 0; Opts = Opts->Next, Count++)
198 {
199 if (Opts->Value.empty() == true)
200 continue;
b2e465d6
AL
201
202 // Determine the protocol version
203 string OptSec = Opts->Value;
204 string::size_type Pos;
205 if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0)
206 Pos = OptSec.length();
b2e465d6
AL
207 OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos);
208
209 unsigned int Version = _config->FindI(OptSec+"::Version",1);
210
db0c350f
AL
211 // Create the pipes
212 int Pipes[2];
213 if (pipe(Pipes) != 0)
214 return _error->Errno("pipe","Failed to create IPC pipe to subprocess");
215 SetCloseExec(Pipes[0],true);
216 SetCloseExec(Pipes[1],true);
217
218 // Purified Fork for running the script
219 pid_t Process = ExecFork();
220 if (Process == 0)
221 {
222 // Setup the FDs
223 dup2(Pipes[0],STDIN_FILENO);
224 SetCloseExec(STDOUT_FILENO,false);
225 SetCloseExec(STDIN_FILENO,false);
226 SetCloseExec(STDERR_FILENO,false);
90ecbd7d
AL
227
228 const char *Args[4];
db0c350f 229 Args[0] = "/bin/sh";
90ecbd7d
AL
230 Args[1] = "-c";
231 Args[2] = Opts->Value.c_str();
232 Args[3] = 0;
db0c350f
AL
233 execv(Args[0],(char **)Args);
234 _exit(100);
235 }
236 close(Pipes[0]);
b2e465d6
AL
237 FILE *F = fdopen(Pipes[1],"w");
238 if (F == 0)
239 return _error->Errno("fdopen","Faild to open new FD");
240
db0c350f 241 // Feed it the filenames.
b2e465d6
AL
242 bool Die = false;
243 if (Version <= 1)
db0c350f 244 {
b2e465d6 245 for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
db0c350f 246 {
b2e465d6
AL
247 // Only deal with packages to be installed from .deb
248 if (I->Op != Item::Install)
249 continue;
250
251 // No errors here..
252 if (I->File[0] != '/')
253 continue;
254
255 /* Feed the filename of each package that is pending install
256 into the pipe. */
257 fprintf(F,"%s\n",I->File.c_str());
258 if (ferror(F) != 0)
259 {
260 Die = true;
261 break;
262 }
90ecbd7d 263 }
db0c350f 264 }
b2e465d6
AL
265 else
266 Die = !SendV2Pkgs(F);
267
268 fclose(F);
db0c350f
AL
269
270 // Clean up the sub process
271 if (ExecWait(Process,Opts->Value.c_str()) == false)
90ecbd7d 272 return _error->Error("Failure running script %s",Opts->Value.c_str());
db0c350f
AL
273 }
274
275 return true;
276}
03e39e59
AL
277 /*}}}*/
278// DPkgPM::Go - Run the sequence /*{{{*/
279// ---------------------------------------------------------------------
75ef8f14
MV
280/* This globs the operations and calls dpkg
281 *
282 * If it is called with "OutStatusFd" set to a valid file descriptor
283 * apt will report the install progress over this fd. It maps the
284 * dpkg states a package goes through to human readable (and i10n-able)
285 * names and calculates a percentage for each step.
286*/
287bool pkgDPkgPM::Go(int OutStatusFd)
03e39e59 288{
6b8147b8
MZ
289 unsigned int MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024);
290 unsigned int MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024);
aff4e2f1 291
6dd55be7
AL
292 if (RunScripts("DPkg::Pre-Invoke") == false)
293 return false;
db0c350f
AL
294
295 if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false)
296 return false;
75ef8f14
MV
297
298 // prepare the progress reporting
299 int Done = 0;
300 int Total = 0;
301 // map the dpkg states to the operations that are performed
302 // (this is sorted in the same way as Item::Ops)
303 static const struct DpkgState DpkgStatesOpMap[][5] = {
304 // Install operation
305 {
306 {"half-installed", _("Preparing %s")},
307 {"unpacked", _("Unpacking %s") },
308 {NULL, NULL}
309 },
310 // Configure operation
311 {
312 {"unpacked",_("Preparing to configure %s") },
313 {"half-configured", _("Configuring %s") },
314 { "installed", _("Installed %s")},
315 {NULL, NULL}
316 },
317 // Remove operation
318 {
319 {"half-configured", _("Preparing for removal of %s")},
320 {"half-installed", _("Removing %s")},
321 {"config-files", _("Removed %s")},
322 {NULL, NULL}
323 },
324 // Purge operation
325 {
0e36721c
MV
326 {"config-files", _("Preparing to completely remove %s")},
327 {"not-installed", _("Completely removed %s")},
75ef8f14
MV
328 {NULL, NULL}
329 },
330 };
db0c350f 331
75ef8f14
MV
332 // the dpkg states that the pkg will run through, the string is
333 // the package, the vector contains the dpkg states that the package
334 // will go through
335 map<string,vector<struct DpkgState> > PackageOps;
336 // the dpkg states that are already done; the string is the package
337 // the int is the state that is already done (e.g. a package that is
338 // going to be install is already in state "half-installed")
339 map<string,int> PackageOpsDone;
340
341 // init the PackageOps map, go over the list of packages that
342 // that will be [installed|configured|removed|purged] and add
343 // them to the PackageOps map (the dpkg states it goes through)
344 // and the PackageOpsTranslations (human readable strings)
345 for (vector<Item>::iterator I = List.begin(); I != List.end();I++)
346 {
347 string name = (*I).Pkg.Name();
348 PackageOpsDone[name] = 0;
349 for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; i++)
350 {
351 PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]);
352 Total++;
353 }
354 }
355
356 // this loop is runs once per operation
03e39e59
AL
357 for (vector<Item>::iterator I = List.begin(); I != List.end();)
358 {
359 vector<Item>::iterator J = I;
360 for (; J != List.end() && J->Op == I->Op; J++);
30e1eab5 361
03e39e59 362 // Generate the argument list
aff4e2f1
AL
363 const char *Args[MaxArgs + 50];
364 if (J - I > (signed)MaxArgs)
365 J = I + MaxArgs;
03e39e59 366
30e1eab5
AL
367 unsigned int n = 0;
368 unsigned long Size = 0;
43b3b626 369 string Tmp = _config->Find("Dir::Bin::dpkg","dpkg");
50914ffa 370 Args[n++] = Tmp.c_str();
30e1eab5 371 Size += strlen(Args[n-1]);
03e39e59 372
6dd55be7
AL
373 // Stick in any custom dpkg options
374 Configuration::Item const *Opts = _config->Tree("DPkg::Options");
375 if (Opts != 0)
376 {
377 Opts = Opts->Child;
378 for (; Opts != 0; Opts = Opts->Next)
379 {
380 if (Opts->Value.empty() == true)
381 continue;
382 Args[n++] = Opts->Value.c_str();
383 Size += Opts->Value.length();
384 }
385 }
386
007dc9e0 387 char status_fd_buf[20];
75ef8f14
MV
388 int fd[2];
389 pipe(fd);
390
391 Args[n++] = "--status-fd";
392 Size += strlen(Args[n-1]);
393 snprintf(status_fd_buf,sizeof(status_fd_buf),"%i", fd[1]);
394 Args[n++] = status_fd_buf;
395 Size += strlen(Args[n-1]);
007dc9e0 396
03e39e59
AL
397 switch (I->Op)
398 {
399 case Item::Remove:
400 Args[n++] = "--force-depends";
30e1eab5 401 Size += strlen(Args[n-1]);
03e39e59 402 Args[n++] = "--force-remove-essential";
30e1eab5 403 Size += strlen(Args[n-1]);
03e39e59 404 Args[n++] = "--remove";
30e1eab5 405 Size += strlen(Args[n-1]);
03e39e59
AL
406 break;
407
fc4b5c9f
AL
408 case Item::Purge:
409 Args[n++] = "--force-depends";
410 Size += strlen(Args[n-1]);
411 Args[n++] = "--force-remove-essential";
412 Size += strlen(Args[n-1]);
413 Args[n++] = "--purge";
414 Size += strlen(Args[n-1]);
415 break;
416
03e39e59
AL
417 case Item::Configure:
418 Args[n++] = "--configure";
30e1eab5 419 Size += strlen(Args[n-1]);
03e39e59
AL
420 break;
421
422 case Item::Install:
423 Args[n++] = "--unpack";
30e1eab5 424 Size += strlen(Args[n-1]);
03e39e59
AL
425 break;
426 }
427
428 // Write in the file or package names
429 if (I->Op == Item::Install)
30e1eab5 430 {
aff4e2f1 431 for (;I != J && Size < MaxArgBytes; I++)
30e1eab5 432 {
cf544e14
AL
433 if (I->File[0] != '/')
434 return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
03e39e59 435 Args[n++] = I->File.c_str();
30e1eab5
AL
436 Size += strlen(Args[n-1]);
437 }
438 }
03e39e59 439 else
30e1eab5 440 {
aff4e2f1 441 for (;I != J && Size < MaxArgBytes; I++)
30e1eab5 442 {
03e39e59 443 Args[n++] = I->Pkg.Name();
30e1eab5
AL
444 Size += strlen(Args[n-1]);
445 }
446 }
03e39e59 447 Args[n] = 0;
30e1eab5
AL
448 J = I;
449
450 if (_config->FindB("Debug::pkgDPkgPM",false) == true)
451 {
452 for (unsigned int k = 0; k != n; k++)
453 clog << Args[k] << ' ';
454 clog << endl;
455 continue;
456 }
03e39e59 457
03e39e59
AL
458 cout << flush;
459 clog << flush;
460 cerr << flush;
461
462 /* Mask off sig int/quit. We do this because dpkg also does when
463 it forks scripts. What happens is that when you hit ctrl-c it sends
464 it to all processes in the group. Since dpkg ignores the signal
465 it doesn't die but we do! So we must also ignore it */
7f9a6360
AL
466 sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN);
467 sighandler_t old_SIGINT = signal(SIGINT,SIG_IGN);
75ef8f14
MV
468
469 // Fork dpkg
007dc9e0 470 pid_t Child;
75ef8f14
MV
471 _config->Set("APT::Keep-Fds::",fd[1]);
472 Child = ExecFork();
6dd55be7 473
03e39e59
AL
474 // This is the child
475 if (Child == 0)
476 {
75ef8f14
MV
477 close(fd[0]); // close the read end of the pipe
478
cf544e14 479 if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
0dbb95d8 480 _exit(100);
03e39e59 481
421ff807 482 if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO))
8b5fe26c
AL
483 {
484 int Flags,dummy;
485 if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
486 _exit(100);
487
488 // Discard everything in stdin before forking dpkg
489 if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
490 _exit(100);
491
492 while (read(STDIN_FILENO,&dummy,1) == 1);
493
494 if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
495 _exit(100);
496 }
03e39e59 497
03e39e59
AL
498 /* No Job Control Stop Env is a magic dpkg var that prevents it
499 from using sigstop */
101030ab 500 putenv("DPKG_NO_TSTP=yes");
d568ed2d 501 execvp(Args[0],(char **)Args);
03e39e59 502 cerr << "Could not exec dpkg!" << endl;
0dbb95d8 503 _exit(100);
03e39e59
AL
504 }
505
75ef8f14
MV
506 // clear the Keep-Fd again
507 _config->Clear("APT::Keep-Fds",fd[1]);
508
03e39e59
AL
509 // Wait for dpkg
510 int Status = 0;
75ef8f14
MV
511
512 // we read from dpkg here
513 int _dpkgin = fd[0];
514 fcntl(_dpkgin, F_SETFL, O_NONBLOCK);
515 close(fd[1]); // close the write end of the pipe
516
517 // the read buffers for the communication with dpkg
518 char line[1024] = {0,};
519 char buf[2] = {0,0};
520
521 // the result of the waitpid call
522 int res;
523
524 while ((res=waitpid(Child,&Status, WNOHANG)) != Child) {
525 if(res < 0) {
526 // FIXME: move this to a function or something, looks ugly here
527 // error handling, waitpid returned -1
528 if (errno == EINTR)
529 continue;
530 RunScripts("DPkg::Post-Invoke");
531
532 // Restore sig int/quit
533 signal(SIGQUIT,old_SIGQUIT);
534 signal(SIGINT,old_SIGINT);
535 return _error->Errno("waitpid","Couldn't wait for subprocess");
536 }
537
538 // read a single char, make sure that the read can't block
539 // (otherwise we may leave zombies)
540 int len = read(_dpkgin, buf, 1);
541
542 // nothing to read, wait a bit for more
543 if(len <= 0)
544 {
545 usleep(1000);
03e39e59 546 continue;
75ef8f14
MV
547 }
548
549 // sanity check (should never happen)
550 if(strlen(line) >= sizeof(line)-10)
551 {
552 _error->Error("got a overlong line from dpkg: '%s'",line);
553 line[0]=0;
554 }
555 // append to line, check if we got a complete line
556 strcat(line, buf);
557 if(buf[0] != '\n')
558 continue;
559
560 if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
561 std::clog << "got from dpkg '" << line << "'" << std::endl;
562
563 // the status we output
564 ostringstream status;
565
566 /* dpkg sends strings like this:
567 'status: <pkg>: <pkg qstate>'
568 errors look like this:
569 '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
570 and conffile-prompt like this
571 'status: conffile-prompt: conffile : 'current-conffile' 'new-conffile' useredited distedited
572
573 */
eda1bb3c
MV
574 char* list[5];
575 TokSplitString(':', line, list, sizeof(list)/sizeof(list[0]));
75ef8f14
MV
576 char *pkg = list[1];
577 char *action = _strstrip(list[2]);
578
579 if(strncmp(action,"error",strlen("error")) == 0)
580 {
581 status << "pmerror:" << list[1]
582 << ":" << (Done/float(Total)*100.0)
583 << ":" << list[3]
584 << endl;
585 if(OutStatusFd > 0)
586 write(OutStatusFd, status.str().c_str(), status.str().size());
587 line[0]=0;
588 if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
589 std::clog << "send: '" << status.str() << "'" << endl;
590 continue;
591 }
592 if(strncmp(action,"conffile",strlen("conffile")) == 0)
593 {
594 status << "pmconffile:" << list[1]
595 << ":" << (Done/float(Total)*100.0)
596 << ":" << list[3]
597 << endl;
598 if(OutStatusFd > 0)
599 write(OutStatusFd, status.str().c_str(), status.str().size());
600 line[0]=0;
601 if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
602 std::clog << "send: '" << status.str() << "'" << endl;
603 continue;
604 }
605
606 vector<struct DpkgState> &states = PackageOps[pkg];
607 const char *next_action = NULL;
608 if(PackageOpsDone[pkg] < states.size())
609 next_action = states[PackageOpsDone[pkg]].state;
610 // check if the package moved to the next dpkg state
611 if(next_action && (strcmp(action, next_action) == 0))
612 {
613 // only read the translation if there is actually a next
614 // action
615 const char *translation = states[PackageOpsDone[pkg]].str;
616 char s[200];
617 snprintf(s, sizeof(s), translation, pkg);
618
619 // we moved from one dpkg state to a new one, report that
620 PackageOpsDone[pkg]++;
621 Done++;
622 // build the status str
623 status << "pmstatus:" << pkg
624 << ":" << (Done/float(Total)*100.0)
625 << ":" << s
626 << endl;
627 if(OutStatusFd > 0)
628 write(OutStatusFd, status.str().c_str(), status.str().size());
629 if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
630 std::clog << "send: '" << status.str() << "'" << endl;
631
632 }
633 if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
634 std::clog << "(parsed from dpkg) pkg: " << pkg
635 << " action: " << action << endl;
7f9a6360 636
75ef8f14
MV
637 // reset the line buffer
638 line[0]=0;
03e39e59 639 }
75ef8f14 640 close(_dpkgin);
03e39e59
AL
641
642 // Restore sig int/quit
7f9a6360
AL
643 signal(SIGQUIT,old_SIGQUIT);
644 signal(SIGINT,old_SIGINT);
6dd55be7
AL
645
646 // Check for an error code.
647 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
648 {
649 RunScripts("DPkg::Post-Invoke");
f956efb4 650 if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
b2e465d6
AL
651 return _error->Error("Sub-process %s received a segmentation fault.",Args[0]);
652
f956efb4 653 if (WIFEXITED(Status) != 0)
0410b3d5 654 return _error->Error("Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status));
f956efb4 655
0410b3d5 656 return _error->Error("Sub-process %s exited unexpectedly",Args[0]);
6dd55be7 657 }
03e39e59 658 }
6dd55be7
AL
659
660 if (RunScripts("DPkg::Post-Invoke") == false)
661 return false;
03e39e59
AL
662 return true;
663}
664 /*}}}*/
281daf46
AL
665// pkgDpkgPM::Reset - Dump the contents of the command list /*{{{*/
666// ---------------------------------------------------------------------
667/* */
668void pkgDPkgPM::Reset()
669{
670 List.erase(List.begin(),List.end());
671}
672 /*}}}*/