dpkgpm.cc 19 KB

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