dpkgpm.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: dpkgpm.cc,v 1.2 1998/11/22 03:20:35 jgg 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 <unistd.h>
  16. #include <stdlib.h>
  17. #include <fcntl.h>
  18. #include <sys/types.h>
  19. #include <sys/wait.h>
  20. #include <signal.h>
  21. #include <errno.h>
  22. /*}}}*/
  23. // DPkgPM::pkgDPkgPM - Constructor /*{{{*/
  24. // ---------------------------------------------------------------------
  25. /* */
  26. pkgDPkgPM::pkgDPkgPM(pkgDepCache &Cache) : pkgPackageManager(Cache)
  27. {
  28. }
  29. /*}}}*/
  30. // DPkgPM::pkgDPkgPM - Destructor /*{{{*/
  31. // ---------------------------------------------------------------------
  32. /* */
  33. pkgDPkgPM::~pkgDPkgPM()
  34. {
  35. }
  36. /*}}}*/
  37. // DPkgPM::Install - Install a package /*{{{*/
  38. // ---------------------------------------------------------------------
  39. /* Add an install operation to the sequence list */
  40. bool pkgDPkgPM::Install(PkgIterator Pkg,string File)
  41. {
  42. if (File.empty() == true || Pkg.end() == true)
  43. return _error->Error("Internal Error, No file name for %s",Pkg.Name());
  44. List.push_back(Item(Item::Install,Pkg,File));
  45. return true;
  46. }
  47. /*}}}*/
  48. // DPkgPM::Configure - Configure a package /*{{{*/
  49. // ---------------------------------------------------------------------
  50. /* Add a configure operation to the sequence list */
  51. bool pkgDPkgPM::Configure(PkgIterator Pkg)
  52. {
  53. if (Pkg.end() == true)
  54. return false;
  55. List.push_back(Item(Item::Configure,Pkg));
  56. return true;
  57. }
  58. /*}}}*/
  59. // DPkgPM::Remove - Remove a package /*{{{*/
  60. // ---------------------------------------------------------------------
  61. /* Add a remove operation to the sequence list */
  62. bool pkgDPkgPM::Remove(PkgIterator Pkg)
  63. {
  64. if (Pkg.end() == true)
  65. return false;
  66. List.push_back(Item(Item::Remove,Pkg));
  67. return true;
  68. }
  69. /*}}}*/
  70. // DPkgPM::Go - Run the sequence /*{{{*/
  71. // ---------------------------------------------------------------------
  72. /* This globs the operations and calls dpkg */
  73. bool pkgDPkgPM::Go()
  74. {
  75. for (vector<Item>::iterator I = List.begin(); I != List.end();)
  76. {
  77. vector<Item>::iterator J = I;
  78. for (; J != List.end() && J->Op == I->Op; J++);
  79. // Generate the argument list
  80. const char *Args[400];
  81. if (J - I > 350)
  82. J = I + 350;
  83. unsigned int n = 0;
  84. unsigned long Size = 0;
  85. Args[n++] = _config->Find("Dir::Bin::dpkg","dpkg").c_str();
  86. Size += strlen(Args[n-1]);
  87. switch (I->Op)
  88. {
  89. case Item::Remove:
  90. Args[n++] = "--force-depends";
  91. Size += strlen(Args[n-1]);
  92. Args[n++] = "--force-remove-essential";
  93. Size += strlen(Args[n-1]);
  94. Args[n++] = "--remove";
  95. Size += strlen(Args[n-1]);
  96. break;
  97. case Item::Configure:
  98. Args[n++] = "--configure";
  99. Size += strlen(Args[n-1]);
  100. break;
  101. case Item::Install:
  102. Args[n++] = "--unpack";
  103. Size += strlen(Args[n-1]);
  104. break;
  105. }
  106. // Write in the file or package names
  107. if (I->Op == Item::Install)
  108. {
  109. for (;I != J && Size < 1024; I++)
  110. {
  111. Args[n++] = I->File.c_str();
  112. Size += strlen(Args[n-1]);
  113. }
  114. }
  115. else
  116. {
  117. for (;I != J && Size < 1024; I++)
  118. {
  119. Args[n++] = I->Pkg.Name();
  120. Size += strlen(Args[n-1]);
  121. }
  122. }
  123. Args[n] = 0;
  124. J = I;
  125. if (_config->FindB("Debug::pkgDPkgPM",false) == true)
  126. {
  127. for (unsigned int k = 0; k != n; k++)
  128. clog << Args[k] << ' ';
  129. clog << endl;
  130. continue;
  131. }
  132. cout << flush;
  133. clog << flush;
  134. cerr << flush;
  135. /* Mask off sig int/quit. We do this because dpkg also does when
  136. it forks scripts. What happens is that when you hit ctrl-c it sends
  137. it to all processes in the group. Since dpkg ignores the signal
  138. it doesn't die but we do! So we must also ignore it */
  139. signal(SIGQUIT,SIG_IGN);
  140. signal(SIGINT,SIG_IGN);
  141. // Fork dpkg
  142. pid_t Child = fork();
  143. if (Child < 0)
  144. return _error->Errno("fork","Could't fork");
  145. // This is the child
  146. if (Child == 0)
  147. {
  148. signal(SIGQUIT,SIG_DFL);
  149. signal(SIGINT,SIG_DFL);
  150. signal(SIGWINCH,SIG_DFL);
  151. signal(SIGCONT,SIG_DFL);
  152. signal(SIGTSTP,SIG_DFL);
  153. if (chdir(_config->FindDir("Dir::Cache::Archives").c_str()) != 0)
  154. exit(100);
  155. // Close all of our FDs - just in case
  156. for (int K = 3; K != 40; K++)
  157. fcntl(K,F_SETFD,FD_CLOEXEC);
  158. int Flags,dummy;
  159. if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
  160. exit(100);
  161. // Discard everything in stdin before forking dpkg
  162. if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
  163. exit(100);
  164. while (read(STDIN_FILENO,&dummy,1) == 1);
  165. if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
  166. exit(100);
  167. /* No Job Control Stop Env is a magic dpkg var that prevents it
  168. from using sigstop */
  169. setenv("DPKG_NO_TSTP","yes",1);
  170. execvp("dpkg",(char **)Args);
  171. cerr << "Could not exec dpkg!" << endl;
  172. exit(100);
  173. }
  174. // Wait for dpkg
  175. int Status = 0;
  176. while (waitpid(Child,&Status,0) != Child)
  177. {
  178. if (errno == EINTR)
  179. continue;
  180. return _error->Errno("waitpid","Couldn't wait for subprocess");
  181. }
  182. // Check for an error code.
  183. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
  184. return _error->Error("Sub-process returned an error code");
  185. // Restore sig int/quit
  186. signal(SIGQUIT,SIG_DFL);
  187. signal(SIGINT,SIG_DFL);
  188. }
  189. return true;
  190. }
  191. /*}}}*/