You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

725 lines
20 KiB

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