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