acquire-worker.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: acquire-worker.cc,v 1.2 1998/10/20 02:39:13 jgg Exp $
  4. /* ######################################################################
  5. Acquire Worker
  6. The worker process can startup either as a Configuration prober
  7. or as a queue runner. As a configuration prober it only reads the
  8. configuration message and
  9. ##################################################################### */
  10. /*}}}*/
  11. // Include Files /*{{{*/
  12. #ifdef __GNUG__
  13. #pragma implementation "apt-pkg/acquire-worker.h"
  14. #endif
  15. #include <apt-pkg/acquire-worker.h>
  16. #include <apt-pkg/configuration.h>
  17. #include <apt-pkg/error.h>
  18. #include <apt-pkg/fileutl.h>
  19. #include <strutl.h>
  20. #include <unistd.h>
  21. #include <signal.h>
  22. /*}}}*/
  23. // Worker::Worker - Constructor for Queue startup /*{{{*/
  24. // ---------------------------------------------------------------------
  25. /* */
  26. pkgAcquire::Worker::Worker(Queue *Q,string Acc)
  27. {
  28. OwnerQ = Q;
  29. Config = 0;
  30. Access = Acc;
  31. Construct();
  32. }
  33. /*}}}*/
  34. // Worker::Worker - Constructor for method config startup /*{{{*/
  35. // ---------------------------------------------------------------------
  36. /* */
  37. pkgAcquire::Worker::Worker(MethodConfig *Cnf)
  38. {
  39. OwnerQ = 0;
  40. Config = Cnf;
  41. Access = Cnf->Access;
  42. Construct();
  43. }
  44. /*}}}*/
  45. // Worker::Construct - Constructor helper /*{{{*/
  46. // ---------------------------------------------------------------------
  47. /* */
  48. void pkgAcquire::Worker::Construct()
  49. {
  50. Next = 0;
  51. Process = -1;
  52. InFd = -1;
  53. OutFd = -1;
  54. Debug = _config->FindB("Debug::pkgAcquire::Worker",false);
  55. }
  56. /*}}}*/
  57. // Worker::~Worker - Destructor /*{{{*/
  58. // ---------------------------------------------------------------------
  59. /* */
  60. pkgAcquire::Worker::~Worker()
  61. {
  62. close(InFd);
  63. close(OutFd);
  64. if (Process > 0)
  65. kill(Process,SIGINT);
  66. }
  67. /*}}}*/
  68. // Worker::Start - Start the worker process /*{{{*/
  69. // ---------------------------------------------------------------------
  70. /* This forks the method and inits the communication channel */
  71. bool pkgAcquire::Worker::Start()
  72. {
  73. // Get the method path
  74. string Method = _config->FindDir("Dir::Bin::Methods") + Access;
  75. if (FileExists(Method) == false)
  76. return _error->Error("The method driver %s could not be found.",Method.c_str());
  77. if (Debug == true)
  78. clog << "Starting method '" << Method << '\'' << endl;
  79. // Create the pipes
  80. int Pipes[4] = {-1,-1,-1,-1};
  81. if (pipe(Pipes) != 0 || pipe(Pipes+2) != 0)
  82. {
  83. _error->Errno("pipe","Failed to create IPC pipe to subprocess");
  84. for (int I = 0; I != 4; I++)
  85. close(Pipes[I]);
  86. return false;
  87. }
  88. // Fork off the process
  89. Process = fork();
  90. if (Process < 0)
  91. {
  92. cerr << "FATAL -> Failed to fork." << endl;
  93. exit(100);
  94. }
  95. // Spawn the subprocess
  96. if (Process == 0)
  97. {
  98. // Setup the FDs
  99. dup2(Pipes[1],STDOUT_FILENO);
  100. dup2(Pipes[2],STDIN_FILENO);
  101. dup2(((filebuf *)clog.rdbuf())->fd(),STDERR_FILENO);
  102. for (int I = 0; I != 4; I++)
  103. close(Pipes[I]);
  104. SetCloseExec(STDOUT_FILENO,false);
  105. SetCloseExec(STDIN_FILENO,false);
  106. SetCloseExec(STDERR_FILENO,false);
  107. const char *Args[2];
  108. Args[0] = Method.c_str();
  109. Args[1] = 0;
  110. execv(Args[0],(char **)Args);
  111. cerr << "Failed to exec method " << Args[0] << endl;
  112. exit(100);
  113. }
  114. // Fix up our FDs
  115. InFd = Pipes[0];
  116. OutFd = Pipes[3];
  117. SetNonBlock(Pipes[0],true);
  118. SetNonBlock(Pipes[3],true);
  119. close(Pipes[1]);
  120. close(Pipes[2]);
  121. // Read the configuration data
  122. if (WaitFd(InFd) == false ||
  123. ReadMessages() == false)
  124. return _error->Error("Method %s did not start correctly",Method.c_str());
  125. RunMessages();
  126. return true;
  127. }
  128. /*}}}*/
  129. // Worker::ReadMessages - Read all pending messages into the list /*{{{*/
  130. // ---------------------------------------------------------------------
  131. /* This pulls full messages from the input FD into the message buffer.
  132. It assumes that messages will not pause during transit so no
  133. fancy buffering is used. */
  134. bool pkgAcquire::Worker::ReadMessages()
  135. {
  136. char Buffer[4000];
  137. char *End = Buffer;
  138. while (1)
  139. {
  140. int Res = read(InFd,End,sizeof(Buffer) - (End-Buffer));
  141. // Process is dead, this is kind of bad..
  142. if (Res == 0)
  143. {
  144. if (waitpid(Process,0,0) != Process)
  145. _error->Warning("I waited but nothing was there!");
  146. Process = -1;
  147. close(InFd);
  148. close(OutFd);
  149. InFd = -1;
  150. OutFd = -1;
  151. return false;
  152. }
  153. // No data
  154. if (Res == -1)
  155. return true;
  156. End += Res;
  157. // Look for the end of the message
  158. for (char *I = Buffer; I < End; I++)
  159. {
  160. if (I[0] != '\n' || I[1] != '\n')
  161. continue;
  162. // Pull the message out
  163. string Message(Buffer,0,I-Buffer);
  164. // Fix up the buffer
  165. for (; I < End && *I == '\n'; I++);
  166. End -= I-Buffer;
  167. memmove(Buffer,I,End-Buffer);
  168. I = Buffer;
  169. if (Debug == true)
  170. clog << "Message " << Access << ':' << QuoteString(Message,"\n") << endl;
  171. MessageQueue.push_back(Message);
  172. }
  173. if (End == Buffer)
  174. return true;
  175. if (WaitFd(InFd) == false)
  176. return false;
  177. }
  178. return true;
  179. }
  180. /*}}}*/
  181. // Worker::RunMessage - Empty the message queue /*{{{*/
  182. // ---------------------------------------------------------------------
  183. /* This takes the messages from the message queue and runs them through
  184. the parsers in order. */
  185. bool pkgAcquire::Worker::RunMessages()
  186. {
  187. while (MessageQueue.empty() == false)
  188. {
  189. string Message = MessageQueue.front();
  190. MessageQueue.erase(MessageQueue.begin());
  191. // Fetch the message number
  192. char *End;
  193. int Number = strtol(Message.c_str(),&End,10);
  194. if (End == Message.c_str())
  195. return _error->Error("Invalid message from method %s: %s",Access.c_str(),Message.c_str());
  196. // Determine the message number and dispatch
  197. switch (Number)
  198. {
  199. case 100:
  200. if (Capabilities(Message) == false)
  201. return _error->Error("Unable to process Capabilities message from %s",Access.c_str());
  202. break;
  203. }
  204. }
  205. return true;
  206. }
  207. /*}}}*/
  208. // Worker::Capabilities - 100 Capabilities handler /*{{{*/
  209. // ---------------------------------------------------------------------
  210. /* This parses the capabilities message and dumps it into the configuration
  211. structure. */
  212. bool pkgAcquire::Worker::Capabilities(string Message)
  213. {
  214. if (Config == 0)
  215. return true;
  216. Config->Version = LookupTag(Message,"Version");
  217. Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
  218. Config->PreScan = StringToBool(LookupTag(Message,"Pre-Scan"),false);
  219. // Some debug text
  220. if (Debug == true)
  221. {
  222. clog << "Configured access method " << Config->Access << endl;
  223. clog << "Version: " << Config->Version << " SingleInstance: " <<
  224. Config->SingleInstance << " PreScan: " << Config->PreScan << endl;
  225. }
  226. return true;
  227. }
  228. /*}}}*/