dpkgpm.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: dpkgpm.cc,v 1.9 1999/04/20 05:02:09 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::RunScripts - Run a set of scripts /*{{{*/
  71. // ---------------------------------------------------------------------
  72. /* This looks for a list of script sto run from the configuration file,
  73. each one is run with system from a forked child. */
  74. bool pkgDPkgPM::RunScripts(const char *Cnf)
  75. {
  76. Configuration::Item const *Opts = _config->Tree(Cnf);
  77. if (Opts == 0 || Opts->Child == 0)
  78. return true;
  79. Opts = Opts->Child;
  80. // Fork for running the system calls
  81. pid_t Child = ExecFork();
  82. // This is the child
  83. if (Child == 0)
  84. {
  85. if (chdir("/tmp/") != 0)
  86. _exit(100);
  87. unsigned int Count = 1;
  88. for (; Opts != 0; Opts = Opts->Next, Count++)
  89. {
  90. if (Opts->Value.empty() == true)
  91. continue;
  92. if (system(Opts->Value.c_str()) != 0)
  93. _exit(100+Count);
  94. }
  95. _exit(0);
  96. }
  97. // Wait for the child
  98. int Status = 0;
  99. while (waitpid(Child,&Status,0) != Child)
  100. {
  101. if (errno == EINTR)
  102. continue;
  103. return _error->Errno("waitpid","Couldn't wait for subprocess");
  104. }
  105. // Restore sig int/quit
  106. signal(SIGQUIT,SIG_DFL);
  107. signal(SIGINT,SIG_DFL);
  108. // Check for an error code.
  109. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
  110. {
  111. unsigned int Count = WEXITSTATUS(Status);
  112. if (Count > 100)
  113. {
  114. Count -= 100;
  115. for (; Opts != 0 && Count != 1; Opts = Opts->Next, Count--);
  116. _error->Error("Problem executing scripts %s '%s'",Cnf,Opts->Value.c_str());
  117. }
  118. return _error->Error("Sub-process returned an error code");
  119. }
  120. return true;
  121. }
  122. /*}}}*/
  123. // DPkgPM::Go - Run the sequence /*{{{*/
  124. // ---------------------------------------------------------------------
  125. /* This globs the operations and calls dpkg */
  126. bool pkgDPkgPM::Go()
  127. {
  128. if (RunScripts("DPkg::Pre-Invoke") == false)
  129. return false;
  130. for (vector<Item>::iterator I = List.begin(); I != List.end();)
  131. {
  132. vector<Item>::iterator J = I;
  133. for (; J != List.end() && J->Op == I->Op; J++);
  134. // Generate the argument list
  135. const char *Args[400];
  136. if (J - I > 350)
  137. J = I + 350;
  138. unsigned int n = 0;
  139. unsigned long Size = 0;
  140. Args[n++] = _config->Find("Dir::Bin::dpkg","dpkg").c_str();
  141. Size += strlen(Args[n-1]);
  142. // Stick in any custom dpkg options
  143. Configuration::Item const *Opts = _config->Tree("DPkg::Options");
  144. if (Opts != 0)
  145. {
  146. Opts = Opts->Child;
  147. for (; Opts != 0; Opts = Opts->Next)
  148. {
  149. if (Opts->Value.empty() == true)
  150. continue;
  151. Args[n++] = Opts->Value.c_str();
  152. Size += Opts->Value.length();
  153. }
  154. }
  155. switch (I->Op)
  156. {
  157. case Item::Remove:
  158. Args[n++] = "--force-depends";
  159. Size += strlen(Args[n-1]);
  160. Args[n++] = "--force-remove-essential";
  161. Size += strlen(Args[n-1]);
  162. Args[n++] = "--remove";
  163. Size += strlen(Args[n-1]);
  164. break;
  165. case Item::Configure:
  166. Args[n++] = "--configure";
  167. Size += strlen(Args[n-1]);
  168. break;
  169. case Item::Install:
  170. Args[n++] = "--unpack";
  171. Size += strlen(Args[n-1]);
  172. break;
  173. }
  174. // Write in the file or package names
  175. if (I->Op == Item::Install)
  176. {
  177. for (;I != J && Size < 1024; I++)
  178. {
  179. if (I->File[0] != '/')
  180. return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
  181. Args[n++] = I->File.c_str();
  182. Size += strlen(Args[n-1]);
  183. }
  184. }
  185. else
  186. {
  187. for (;I != J && Size < 1024; I++)
  188. {
  189. Args[n++] = I->Pkg.Name();
  190. Size += strlen(Args[n-1]);
  191. }
  192. }
  193. Args[n] = 0;
  194. J = I;
  195. if (_config->FindB("Debug::pkgDPkgPM",false) == true)
  196. {
  197. for (unsigned int k = 0; k != n; k++)
  198. clog << Args[k] << ' ';
  199. clog << endl;
  200. continue;
  201. }
  202. cout << flush;
  203. clog << flush;
  204. cerr << flush;
  205. /* Mask off sig int/quit. We do this because dpkg also does when
  206. it forks scripts. What happens is that when you hit ctrl-c it sends
  207. it to all processes in the group. Since dpkg ignores the signal
  208. it doesn't die but we do! So we must also ignore it */
  209. signal(SIGQUIT,SIG_IGN);
  210. signal(SIGINT,SIG_IGN);
  211. // Fork dpkg
  212. pid_t Child = ExecFork();
  213. // This is the child
  214. if (Child == 0)
  215. {
  216. if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
  217. _exit(100);
  218. int Flags,dummy;
  219. if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
  220. _exit(100);
  221. // Discard everything in stdin before forking dpkg
  222. if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
  223. _exit(100);
  224. while (read(STDIN_FILENO,&dummy,1) == 1);
  225. if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
  226. _exit(100);
  227. /* No Job Control Stop Env is a magic dpkg var that prevents it
  228. from using sigstop */
  229. setenv("DPKG_NO_TSTP","yes",1);
  230. execvp(Args[0],(char **)Args);
  231. cerr << "Could not exec dpkg!" << endl;
  232. _exit(100);
  233. }
  234. // Wait for dpkg
  235. int Status = 0;
  236. while (waitpid(Child,&Status,0) != Child)
  237. {
  238. if (errno == EINTR)
  239. continue;
  240. RunScripts("DPkg::Post-Invoke");
  241. return _error->Errno("waitpid","Couldn't wait for subprocess");
  242. }
  243. // Restore sig int/quit
  244. signal(SIGQUIT,SIG_DFL);
  245. signal(SIGINT,SIG_DFL);
  246. // Check for an error code.
  247. if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
  248. {
  249. RunScripts("DPkg::Post-Invoke");
  250. if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
  251. return _error->Error("Sub-process recieved a segmentation fault.");
  252. if (WIFEXITED(Status) != 0)
  253. return _error->Error("Sub-process returned an error code (%u)",WEXITSTATUS(Status));
  254. return _error->Error("Sub-process exited unexpectedly");
  255. }
  256. }
  257. if (RunScripts("DPkg::Post-Invoke") == false)
  258. return false;
  259. return true;
  260. }
  261. /*}}}*/